Jump to content

CRYPTO.LIB

From EDM2

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. key is the 8-byte (64-bit) DES key with parity bits; keylen is 8. Returns a pointer to the key schedule in *ks. The schedule must be freed with free_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. iv is 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 len bytes 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, and time to produce a host-unique, time-varying seed.
void DES_rnf(unsigned char *buf, int len)
Fills buf with len pseudo-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. key is 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:

  1. Expand the 8-byte input key through a fixed transformation that zeroes 16 of the 56 key bits, leaving 40 effective key bits.
  2. 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 with find_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_CTX is an opaque structure of approximately 88 bytes containing the running state, bit count, and data buffer. Must be called before MD5Update.
void MD5Update(MD5_CTX *ctx, unsigned char *data, unsigned int len)
Feeds len bytes 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 MD5Final that 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 MD5Update that accepts a pointer-to-pointer, advancing *datap past 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 keylen bytes from a passphrase using MD5, filling key. 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 outlen pseudo-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 len pseudo-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 data using key. 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 for find_mac_sys("KEYED_MD5")
  • mac_keyed_MD5_system — MAC system descriptor for HMAC-MD5
  • mac_MD5_system — MAC system descriptor for plain MD5
  • MD5_prf_system — PRF system descriptor
  • md5_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