CRYPTO.LIB
CRYPTO.LIB is a static cryptographic primitives library included in the IBM OS/2 Developer's Toolkit 4.5 as part of the IBM TCP/IP for OS/2 Version 4.x IP Security (IPsec) subsystem. It was built from sources maintained under IBM's internal IPsec project (path I:\OS2\IPSEC\MKMP\LIBSOURCE\; project code name MKMP). The library provides implementations of DES block encryption, CDMF (Commercial Data Masking Facility), and MD5 hashing, together with a plug-in-style cryptographic algorithm framework used by the IPsec stack for selecting encryption and authentication algorithms at run time.
CRYPTO.LIB is a static library. Its compiled object code is linked directly into the calling application; it has no corresponding DLL. At run time the application depends on OS2386.DLL and TCPIP32.DLL.
File size: 44,442 bytes. No public header distributed in the Toolkit; function signatures must be declared by the caller. Copyright: IBM Corporation. Source modules: md5.C, DES_if.C, md5_if.C, CDMF_if.C, DES_prf.C, DES_rnf.C, md5_prf.C, md5_rnf.C, DES_enc_dec.C, DES_rnf_init.C, md5_rnf_init.C, DES_key_parity.C, DES_str_to_key.C, md5_str_to_key.C.
Purpose and Context
CRYPTO.LIB was produced to support IBM's IPsec implementation for OS/2 TCP/IP 4.x, which provided:
- IPsec AH (Authentication Header) — packet integrity and authentication using HMAC-MD5
- IPsec ESP (Encapsulating Security Payload) — packet confidentiality using DES-CBC
- IKE / ISAKMP — Internet Key Exchange, using MD5 as the pseudo-random function for deriving keying material
The library is present in the Toolkit lib\ directory so that developers building custom VPN client applications, tunnel managers, or IPsec policy tools can link the same cryptographic primitives used by the OS/2 TCP/IP stack itself.
The presence of both DES (56-bit) and CDMF (40-bit weakened) reflects the US export control environment of the mid-1990s: CDMF was IBM's government-approved export variant of DES for international distribution, produced by masking 16 bits of the key.
Algorithm Summary
| Algorithm | Type | Key size | Notes |
|---|---|---|---|
| DES | Block cipher (Feistel) | 56 effective bits (64-bit key with parity) | NIST FIPS 46-3; used for ESP confidentiality |
| CDMF | Block cipher (weakened DES) | 40 effective bits | IBM export variant; IBM patent; reduced to 40-bit security by key masking |
| MD5 | Cryptographic hash | — | 128-bit digest; RFC 1321; used for AH authentication and IKE PRF |
| HMAC-MD5 | MAC | variable | RFC 2104 keyed MD5; primary IPsec AH/ESP authentication algorithm of the era |
Architecture: Crypto System Framework
The library implements a plug-in-style dispatch framework that allows the IPsec stack to select algorithms by name at run time. Each algorithm is registered as a "system" structure providing a uniform interface.
Crypto system (encryption)
/* Opaque algorithm descriptor registered by each cipher */ /* DES_crypto_system, CDMF_crypto_system */ void *find_crypto_sys(char *name); /* look up by name, e.g. "DES", "CDMF" */ void *str_to_crypto_sys(char *name); /* same, alternative entry */ int use_crypto_sys(void *sys, ...); /* invoke the selected cipher system */
MAC system (authentication)
/* mac_keyed_MD5_system, mac_MD5_system */ void *find_mac_sys(char *name); /* look up by name, e.g. "KEYED_MD5" */ void *str_to_mac_sys(char *name); int compute_MAC(void *sys, ...); /* compute authentication tag */ int compute_MAC4(void *sys, ...); /* variant for 4-byte aligned data */ void free_MAC(void *ctx);
PRF system (pseudo-random function)
/* DES_prf_system, MD5_prf_system */ void *find_prf_sys(char *name); void *find_prf_sysx(char *name); void *str_to_prf_sys(char *name);
Key management
int prepare_key(void *sys, unsigned char *key, int keylen); int prepare_keyD(void *sys, unsigned char *key, int keylen); void free_key(void *key); int dup_data_content(void *dst, void *src);
DES Functions
The DES implementation provides standard ECB, CBC, and custom modes. The key schedule is pre-expanded by DES_prepare_key before use.
Key management
int DES_prepare_key(unsigned char *key, int keylen, void **ks)- Expands a raw DES key into a key schedule structure.
keyis the 8-byte (64-bit) DES key with parity bits;keylenis 8. Returns a pointer to the key schedule in*ks. The schedule must be freed withfree_key.
void DES_fix_key_parity(unsigned char *key)- Sets the parity bit (bit 0) of each of the 8 key bytes so that each byte has odd parity, as required by the DES specification. Should be called after generating or importing a DES key.
int DES_key_parity(unsigned char *key)- Checks whether all 8 bytes of the key have correct odd parity. Returns non-zero if parity is correct, 0 otherwise.
int DES_str_to_key(char *passphrase, unsigned char *key)- Derives a DES key from a passphrase string. Folds the string into 8 bytes using a deterministic mixing algorithm and applies parity correction. Not a password hashing function — no salt; use only where the passphrase is itself high-entropy key material.
Encryption / Decryption
void DES_encrypt(unsigned char *block, void *ks)- Encrypts a single 8-byte block in place using the key schedule
ks(ECB mode, one block at a time).
void DES_decrypt(unsigned char *block, void *ks)- Decrypts a single 8-byte block in place.
int DES_enc_dec(int direction, unsigned char *data, int len, void *ks, unsigned char *iv)- Encrypts or decrypts a buffer of arbitrary length (must be a multiple of 8 bytes) using DES-CBC.
direction: 1 = encrypt, 0 = decrypt.ivis the 8-byte initialization vector (updated in place for chaining).
void DES_CBC(unsigned char *data, int len, void *ks, unsigned char *iv, int direction)- Alternative CBC-mode entry point. Processes
lenbytes of data in CBC mode with the supplied IV.
Pseudo-Random Function
void DES_prf(unsigned char *seed, int seedlen, unsigned char *out, int outlen, void *ks)- Generates pseudo-random output using DES as the underlying primitive. Used in IKE for key derivation.
int DES_prf_prepare_key(unsigned char *key, int keylen, void **ks)- Prepares a DES key schedule for PRF use.
Random Number Function
void DES_rnf_init(void)- Initializes the DES-based random number generator. Seeds the generator using
gethostid,_getpid, andtimeto produce a host-unique, time-varying seed.
void DES_rnf(unsigned char *buf, int len)- Fills
bufwithlenpseudo-random bytes generated by iterating DES over an internal state block. Used to generate IKE nonces and ephemeral key material.
Internal Tables
The DES implementation uses precomputed tables stored as static data within the library:
| Symbol | Purpose |
|---|---|
des_keytab |
DES key schedule expansion table |
sbtab |
S-box substitution table |
kseltab |
Key selection permutation table |
des_buf |
Internal working buffer for DES operations |
des_iv |
Default initialization vector storage |
CDMF Functions
CDMF (Commercial Data Masking Facility) is IBM's export-approved variant of DES, published in 1994. It reduces DES's effective key length from 56 bits to 40 bits by a deterministic key-masking step, satisfying US export regulations of the era while retaining the DES block structure.
int CDMF(unsigned char *key, unsigned char *data, int len, int direction)- Encrypts or decrypts
data(multiple of 8 bytes) using the CDMF algorithm.keyis an 8-byte key (only 40 bits are effective after masking).direction: 1 = encrypt, 0 = decrypt.
The CDMF algorithm applies the following key masking before invoking DES:
- Expand the 8-byte input key through a fixed transformation that zeroes 16 of the 56 key bits, leaving 40 effective key bits.
- Use the masked key for standard DES operations.
This design was intended to make CDMF exportable under the US Export Administration Regulations (EAR) of the early 1990s while remaining backward-compatible with DES hardware.
The crypto framework exports:
CDMF_crypto_system— algorithm descriptor for use withfind_crypto_sys("CDMF")CDMF_if— CDMF interface entry points structure
MD5 Functions
The MD5 implementation follows the standard three-call API defined in RFC 1321.
Core hash API
void MD5Init(MD5_CTX *ctx)- Initializes an MD5 context.
MD5_CTXis an opaque structure of approximately 88 bytes containing the running state, bit count, and data buffer. Must be called beforeMD5Update.
void MD5Update(MD5_CTX *ctx, unsigned char *data, unsigned int len)- Feeds
lenbytes of data into the MD5 computation. Can be called multiple times for streaming input.
void MD5Final(unsigned char digest[16], MD5_CTX *ctx)- Finalizes the MD5 computation and writes the 16-byte (128-bit) message digest to
digest. Pads the message and appends the bit count per RFC 1321.
void MD5Finalh(unsigned char *digest, MD5_CTX *ctx)- Variant of
MD5Finalthat may return the digest in half-word (16-bit) or host-byte-order format. Used internally for cross-platform operations.
void MD5UpdateP(MD5_CTX *ctx, unsigned char **datap, unsigned int len)- Variant of
MD5Updatethat accepts a pointer-to-pointer, advancing*datappast the consumed data. Used when processing scatter-gather input buffers.
String-to-key
int md5_str_to_key(char *passphrase, unsigned char *key, int keylen)- Derives key material of length
keylenbytes from a passphrase using MD5, fillingkey. Used in IKE pre-shared-key authentication.
Pseudo-Random Function (PRF)
void md5_prf(unsigned char *seed, int seedlen, unsigned char *out, int outlen, void *ks)- Generates
outlenpseudo-random bytes using MD5 as the PRF. Used in IKE SKEYID derivation and key expansion.
int md5_prf_prepare_key(unsigned char *key, int keylen, void **ks)- Prepares key state for MD5 PRF use.
Random Number Function
void md5_rnf_init(void)- Initializes the MD5-based random number generator with a seed derived from host identity (
gethostid), process ID (_getpid), and current time.
void md5_rnf(unsigned char *buf, int len)- Generates
lenpseudo-random bytes using iterated MD5.
HMAC-MD5 (Keyed MAC)
int mac_keyed_MD5(unsigned char *key, int keylen, unsigned char *data, int datalen, unsigned char *mac)- Computes an HMAC-MD5 authentication tag over
datausingkey. Produces a 16-byte MAC. Implements RFC 2104 HMAC construction with MD5 as the underlying hash.
int mac_MD5(unsigned char *data, int datalen, unsigned char *mac)- Computes a plain (non-keyed) MD5 MAC over
data. Returns the 16-byte MD5 digest as the tag.
The framework exports:
KEYED_MD5— algorithm name constant forfind_mac_sys("KEYED_MD5")mac_keyed_MD5_system— MAC system descriptor for HMAC-MD5mac_MD5_system— MAC system descriptor for plain MD5MD5_prf_system— PRF system descriptormd5_if— MD5 interface structure
Usage
Build Instructions
CRYPTO.LIB is a static library; link it directly. No separate DLL is required beyond the standard TCP/IP libraries.
IBM VisualAge C++ / ILINK
icc -O2 -Gm -c myvpn.c ilink /PM:VIO myvpn.obj os2386.lib tcpip32.lib crypto.lib
OpenWatcom
wcl386 -bt=os2 -mf -c myvpn.c wlink system os2v2 file myvpn.obj library os2386.lib library tcpip32.lib library crypto.lib
EMX/GCC
gcc -Zomf -c myvpn.c gcc -Zomf -o myvpn.exe myvpn.o -los2386 -ltcpip32 -lcrypto
Computing an MD5 digest
/* MD5_CTX is opaque; allocate sufficient space (typically 88 bytes) */
/* No public header: declare manually or use the RFC 1321 structure */
typedef struct {
unsigned long state[4];
unsigned long count[2];
unsigned char buffer[64];
} MD5_CTX;
void MD5Init(MD5_CTX *);
void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
void MD5Final(unsigned char [16], MD5_CTX *);
void ComputeMD5(unsigned char *data, unsigned int len,
unsigned char digest[16])
{
MD5_CTX ctx;
MD5Init(&ctx);
MD5Update(&ctx, data, len);
MD5Final(digest, &ctx);
}
Encrypting with DES-CBC
void DES_prepare_key(unsigned char *key, int keylen, void **ks);
void DES_fix_key_parity(unsigned char *key);
void DES_CBC(unsigned char *data, int len, void *ks,
unsigned char *iv, int direction);
void free_key(void *ks);
BOOL EncryptDES_CBC(unsigned char *key8, /* 8-byte DES key */
unsigned char *iv8, /* 8-byte IV (modified in place) */
unsigned char *data, /* must be multiple of 8 bytes */
int datalen)
{
void *ks;
DES_fix_key_parity(key8);
DES_prepare_key(key8, 8, &ks);
if (!ks) return FALSE;
DES_CBC(data, datalen, ks, iv8, 1 /* encrypt */);
free_key(ks);
return TRUE;
}
Selecting an algorithm via the crypto framework
/* Look up DES by name and use it through the generic interface */
void *find_crypto_sys(char *name);
int use_crypto_sys(void *sys, unsigned char *key, int keylen,
unsigned char *data, int datalen,
unsigned char *iv, int direction);
BOOL EncryptByName(char *algname, unsigned char *key, int keylen,
unsigned char *data, int datalen, unsigned char *iv)
{
void *sys = find_crypto_sys(algname); /* "DES" or "CDMF" */
if (!sys) return FALSE;
return use_crypto_sys(sys, key, keylen, data, datalen, iv, 1) == 0;
}
Security Notes
- DES is obsolete. The 56-bit key can be exhausted by brute force in less than 24 hours with modern hardware (the EFF DES Cracker broke it in 22 hours in 1998). Do not use DES for new applications. Use AES-256 instead.
- CDMF is weaker than DES. Its 40-bit effective key strength makes it trivially breakable by brute force on any modern CPU. Its only purpose was US export compliance in the mid-1990s.
- MD5 is cryptographically broken. Collision attacks against MD5 were demonstrated in 2004 (Wang et al.). MD5 should not be used for digital signatures or certificate integrity. For HMAC-MD5 in IPsec contexts it remains computationally sound for authentication (HMAC is not directly vulnerable to collision attacks on the underlying hash), but SHA-256 is the modern replacement.
- DES_rnf / md5_rnf are not cryptographically strong RNGs for general use. They are seeded from
gethostid+ PID + time, which provides limited entropy. Do not use them to generate long-term keys. - This library is provided for compatibility with the OS/2 TCP/IP 4.x IPsec stack. It should not be used in new security-sensitive applications.
Module Structure
The OMF object modules within CRYPTO.LIB correspond to the original source files:
| Object module | Source file | Contents |
|---|---|---|
md5 |
md5.C |
MD5Init, MD5Update, MD5Final core implementation |
DES_if |
DES_if.C |
DES algorithm interface and crypto_system descriptor |
md5_if |
md5_if.C |
MD5 algorithm interface and system descriptors |
CDMF_if |
CDMF_if.C |
CDMF algorithm interface |
DES_prf |
DES_prf.C |
DES pseudo-random function |
DES_rnf |
DES_rnf.C |
DES random number function |
md5_prf |
md5_prf.C |
MD5 pseudo-random function |
md5_rnf |
md5_rnf.C |
MD5 random number function |
DES_enc_dec |
DES_enc_dec.C |
DES encrypt/decrypt wrapper (CBC mode) |
DES_rnf_init |
DES_rnf_init.C |
DES RNF initialization (seed from host/PID/time) |
md5_rnf_init |
md5_rnf_init.C |
MD5 RNF initialization |
DES_key_parity |
DES_key_parity.C |
DES parity check and fix |
DES_str_to_key |
DES_str_to_key.C |
Passphrase to DES key derivation |
md5_str_to_key |
md5_str_to_key.C |
Passphrase to key material via MD5 |
See Also
- TCPIPDLL.LIB — IBM TCP/IP BSD Sockets library (runtime dependency)
- OS2386.LIB — OS/2 base API import library
- IBM TCP/IP for OS/2
- IBM OS/2 Developer's Toolkit