MD5LIB is a small library (about 5400 bytes) containing an implementation of the MD5 message-digest algorithm and Luby-Rackoff encryption based on MD5. It encrypts at up to 180 bytes/sec on my HP 48SX, and should work at up to 260 bytes/sec on a G or GX. The library is implemented entirely in system RPL and machine language. The functions in the library are: LRE (Luby-Rackoff Encrypt string) Input: 2: plaintext (string) 1: key (string) Output: 1: ciphertext (string) LRD (Luby-Rackoff Decrypt string) Input: same as LRE Output: 2: plaintext (string) 1: 1 (decryption was successful) or 0 (wrong key) LRE and LRD encrypt/decrypt arbitrary HP 48 strings. Strings up to about half the size of available memory can be encrypted/decrypted. The key may be any length; keys of 32 bytes or longer are recommended for better security. To improve encryption security, the MD5 sum of the plaintext string given to LRE is prepended before encryption, and this is compared with the MD5 sum of the string decrypted by LRD. Because Luby-Rackoff encryption works on blocks of 32 bytes, the string is also padded to a multiple of 32 bytes; the total output of LRE is always at least 17 bytes and at most 48 bytes longer than the input. A convenient way to encrypt/decrypt arbitrary HP 48 objects is to use LRE and LRD in conjunction with the BZ compression program, which returns its result as an HP 48 string; since BZ compresses faster than LRE encrypts, this may also improve encryption speed with well-compressible objects. The BZLRE and BZLRD programs below accomplish this: BZLRE: \<< CLLCD SWAP BZ 0 CHR + 3 OVER SIZE SUB SWAP LRE \>> BZLRD: \<< CLLCD IF LRD THEN "BZ" SWAP + UBZ END \>> Because BZ may return "abnormal" string objects that are not an integral number of bytes in length, BZLRE appends a 0 CHR and "normalizes" the string to an integral length using SUB. This does not interfere with the operation of UBZ. LREB (Luby-Rackoff Encrypt Block) Input: 3: key left (string) 2: key right (string) 1: block (32-byte string) Output: 3: key left (string) 2: key right (string) 1: encrypted block (32-byte string) LRDB (Luby-Rackoff Decrypt Block) Input: same as LREB Output: same as LREB, except level 1 is decrypted LREB and LRDB provide a block-level interface to the Luby-Rackoff encryption algorithm for your own applications. MD5 (MD5 sum of string data) Input: 1: string Output: 1: MD5 sum (16-byte string) MD5 computes the MD5 sum of the input string. Since the MD5 sum is 128 bits, it is returned as a 16-byte string because HP 48 hex strings in user RPL are limited to 64 bits. To view the hexadecimal representation of the sum, use the $\->HEX function described below. OBJMD5 (MD5 sum of arbitrary HP 48 object) Input: 1: object Output: 1: MD5 sum (16-byte string) OBJMD5 computes the MD5 sum of an arbitrary HP 48 object. This can be a much better way of verifying the integrity of an object than the CRC checksum returned by BYTES, since the much greater length of an MD5 sum makes it far harder to find a different object with the same sum. Note that the OBJMD5 sum of a string will not be the same as the MD5 sum, because OBJMD5 includes the string prolog and length in the sum; MD5 sums the just the nibbles 16 in the string "a", while OBJMD5 sums the nibbles c2a207000016. SKEYMD5 (MD5-based S/KEY function) Input: 2: seed/secret string 1: sequence number Output: 1: result (64-bit hex string) SKEYMD5 computes the one-way function used by the S/KEY password system. It is primarily provided as a convenience to users of the S/KEY package I wrote for the HP 48. If you are using that package, you can replace the MD5 object in the SKEY directory with the program \<< SKEYMD5 \>> to save memory if you have both SKEY and MD5LIB installed on your calculator. If you are writing your own S/KEY application, note that the sequence number you should give to SKEYMD5 is one more than the sequence number used in the S/KEY challenge -- the extra iteration accomplishes the initial "key crunch". $\->HEX (output hexadecimal representation of string data) Input: 1: string Output: 1: string bytes represented in hexadecimal $\->HEX lets you view MD5 sums (or other string data) as hexadecimal digits, particularly useful for manual verification of MD5 sums. Security: The Luby-Rackoff algorithm is conjectured to be as secure as the underlying hash function used. MD5 has so far resisted full cryptanalysis, but several components of the algorithm have been cryptanalyzed. Should MD5 be cryptanalyzed, this may substantially weaken the encryption used in MD5LIB. However, because Luby-Rackoff can use arbitrary-length keys, and the maximum useful key length in this implementation is probably around 32 bytes (256 bits), substantial progress in cryptanalysis of MD5 would have to be made to badly weaken the algorithm; a key length of 256 bits is at least twice as long as keys used in other algorithms. Probably the biggest threat to the security of your data encrypted with MD5LIB is that HP 48 RPL memory management and object handling will scatter pieces of the plaintext and your key throughout memory. Someone who gets ahold of your calculator immediately after an encryption could extract some or all of the plaintext or your keys by scanning memory. Disabling LASTARG before an encryption or decryption will remove the most obvious threat, which is that a key could be recovered simply by using LASTARG immediately after LRE or LRD. References: You can get everything you need to know about the techniques used in this program from Bruce Schneier's _Applied Cryptography_ (John Wiley & Sons, 1994, ISBN 0-471-59756-2), which covers the Luby-Rackoff algorithm (p. 270, beware of typos), MD5 (p. 329), and CBC mode for block encryption algorithms, as used in LRE and LRD (p. 157).