.TH DES_CRYPT 3 "21 December 1987" .FM mit .AT 3 .SH NAME read_password, string_to_key, random_key, des_set_key, ecb_encrypt, \ cbc_encrypt, pcbc_encrypt, cbc_cksum, quad_cksum \- (new) DES encryption .SH SYNOPSIS .nf .nj .B #include .PP .fi .SH DESCRIPTION This library supports various DES encryption related operations. It differs from the .I crypt, setkey, and encrypt library routines in that it provides a true DES encryption, without modifying the algorithm, and executes much faster. Eight bit bytes are assumed; bit numbers start with the least significant bit. Array and bit indices start with 0. .PP For each key that may be simultaneously active, create a .B Key_schedule structure, defined in "des.h". Next, create key schedules (from the 8-byte keys) as needed, via .I des_set_key, prior to using the encryption or checksum routines. Then setup the input and output areas. Make sure to note the restrictions on lengths being multiples of eight bytes. Finally, invoke the encryption/decryption routines, .I ecb_encrypt or .I cbc_encrypt or .I pcbc_encrypt, or, to generate a cryptographic checksum, use .I quad_cksum (fast) or .I cbc_cksum (slow). .PP A .I C_Block structure is an 8 byte block used as the fundamental unit for DES data and keys, and is defined as follows: .PP .B typedef unsigned char C_Block[8]; .PP A .I Key_schedule is defined as follows, where .I bit_64 is a structure of bit-fields. .PP .B typedef bit_64 Key_schedule[16]; .PP .nf .B int read_password(key, prompt, verify) .B C_Block *key; .B char *prompt; .B int verify; .fi .PP .I read_password writes the string specified by .I prompt to the standard output, turns off echo (if possible) and reads an input string from standard input until terminated with a newline. If .I verify is non-zero, it prompts and reads input again, for use in applications such as changing a password; both versions are compared, and the input is requested repeatedly until they match. Then .I read_password converts the input string into a valid DES key, internally using the .I string_to_key routine. The newly created key is copied to the area pointed to by the .I key argument. .I read_password returns a zero if no errors occurred, or a -1 indicating that an error occurred trying to manipulate the terminal echo. .PP .nf .B int string_to_key(s, k) .B char *s; .B C_Block *k; .fi .PP .I string_to_key converts a null-terminated string of arbitrary length (e.g., a user's password) into an 8 byte DES key, with odd byte parity, per FIPS specification. A one-way function is used to convert the string to a key, making it very difficult to reconstruct the string, given the key. The .I s argument is a pointer to the string, and .I k should point to a .I C_Block supplied by the caller to receive the generated key. No meaningful value is returned. Void is not used for compatibility with other compilers. The algorithm for the conversion is described below. .PP The first step is to flatten the input string into a stream of 7*length(s) bits .I b as follows: .sp .nf b[0] = bit 0 of s[0] b[1] = bit 1 of s[0] ... b[6] = bit 6 of s[0] b[7] = bit 0 of s[1] b[8] = bit 1 of s[1] ... b[7n + m] (0<=m<=6) = bit m of s[n] .sp .fi In other words, the eighth (most significant) bit of each byte of .I s is dropped, and the other bits are shifted over to fill in the gaps. .PP The second step is to "fan-fold" and XOR .I b into a string .I b' exactly 56 bits long. For example, if .I b is 63 bits long: .nf .sp b'[55] = b[55] XOR b[56], b'[54] = b[54] XOR b[57], ... b'[49] = b[49] XOR b[62] .sp .fi (The two steps described above can easily be combined.) .PP A DES key is 8 bytes long, but with odd parity in each byte; the least significant bit of the byte is the parity bit. The DES key is formed from .I b' above in two steps. The first step is to form the key with zero parity as follows: .nf .sp bit 1 of k[0] = b'[0] bit 2 of k[0] = b'[1] bit 1 of k[1] = b'[7] ... bit m of k[n] = b'[7n+m-1] (1<=m<=7) and bit 0 of k[n] = 0 .sp .fi In other words, a zero parity bit is inserted into the stream .I b' every seven bits, resulting in the array .I k of eight 8-bit bytes. The second step is to set or clear the parity bit in each byte of .I k as appropriate. .PP Next, the key schedule of .I k is computed using .I key_sched. Then the 64 bit CBC checksum of the original string is computed (using .I cbc_cksum), and finally, the CBC checksum is forced to odd parity. The generated checksum is the resulting key. .PP .nf .B int random_key(key) .B C_Block *key; .fi .PP .I random_key generates a random DES encryption key (eight bytes), set to odd parity per FIPS specifications. This routine uses the current time, process ID, and a counter as a seed for the random number generator. The caller must supply space for the output key, pointed to by the argument .I key, then after calling .I random_key should call the .I des_set_key routine when needed. No meaningful value is returned. Void is not used for compatibility with other compilers. .PP .nf .B int des_set_key(key, schedule) .B C_Block *key; .B Key_schedule schedule; .fi .PP .I des_set_key calculates a key schedule from all eight bytes of the input key, pointed to by the .I key argument, and outputs the schedule into the .I Key_schedule indicated by the .I schedule argument. Make sure to pass a valid eight byte key; no padding is done. The key schedule may then be used in subsequent encryption/decryption/checksum operations. Many key schedules may be cached for later use. The user is responsible for clearing keys and schedules as soon as they are no longer needed, to prevent their disclosure. The routine also checks the key parity, and returns a zero if the key parity is correct (odd), a -1 indicating a key parity error, or a -2 indicating use of an illegal weak key. If an error is returned, the key schedule was not created. .PP .nf .B int ecb_encrypt(input, output, schedule, encrypt) .B C_Block *input; .B C_Block *output; .B Key_schedule schedule; .B int encrypt; .fi .PP .I ecb_encrypt is the basic DES encryption routine that encrypts or decrypts a single 8-byte block in .B electronic code book mode. It always transforms the input data, pointed to by .I input, into the output data, pointed to by the .I output argument. .PP If the .I encrypt argument is non-zero, the .I input (cleartext) is encrypted into the .I output (ciphertext) using the key_schedule specified by the .I schedule argument, previously set via .I des_set_key .PP If encrypt is zero, the .I input (now ciphertext) is decrypted into the .I output (now cleartext). .PP Input and output may overlap. .PP No meaningful value is returned. Void is not used for compatibility with other compilers. .PP .nf .B int cbc_encrypt(input, output, length, schedule, ivec, encrypt) .B C_Block *input; .B C_Block *output; .B long length; .B Key_schedule schedule; .B C_Block *ivec; .B int encrypt; .fi .PP .I cbc_encrypt encrypts/decrypts using the .B cipher-block-chaining mode of DES. If the .I encrypt argument is non-zero, the routine cipher-block-chain encrypts the cleartext data pointed to by the .I input argument into the ciphertext pointed to by the .I output argument, using the key schedule provided by the .I schedule argument, and initialization vector provided by the .I ivec argument. If the .I length argument is not an integral multiple of eight bytes, the last block is copied to a temp and zero filled (highest addresses). The output is ALWAYS an integral multiple of eight bytes. .PP If .I encrypt is zero, the routine cipher-block chain decrypts the (now) ciphertext data pointed to by the .I input argument into (now) cleartext pointed to by the .I output argument using the key schedule provided by the .I schedule argument, and initialization vector provided by the .I ivec argument. Decryption ALWAYS operates on integral multiples of 8 bytes, so it will round the .I length provided up to the appropriate multiple. Consequently, it will always produce the rounded-up number of bytes of output cleartext. The application must determine if the output cleartext was zero-padded due to original cleartext lengths that were not integral multiples of 8. .PP No errors or meaningful values are returned. Void is not used for compatibility with other compilers. .PP A characteristic of cbc mode is that changing a single bit of the cleartext, then encrypting using cbc mode, affects ALL the subsequent ciphertext. This makes cryptanalysis much more difficult. However, modifying a single bit of the ciphertext, then decrypting, only affects the resulting cleartext from the modified block and the succeeding block. Therefore, .I pcbc_encrypt is STRONGLY recommended for applications where indefinite propagation of errors is required in order to detect modifications. .PP .nf .B int pcbc_encrypt(input, output, length, schedule, ivec, encrypt) .B C_Block *input; .B C_Block *output; .B long length; .B Key_schedule schedule; .B C_Block *ivec; .B int encrypt; .fi .PP .I pcbc_encrypt encrypts/decrypts using a modified block chaining mode. Its calling sequence is identical to .I cbc_encrypt. It differs in its error propagation characteristics. .PP .I pcbc_encrypt is highly recommended for most encryption purposes, in that modification of a single bit of the ciphertext will affect ALL the subsequent (decrypted) cleartext. Similarly, modifying a single bit of the cleartext will affect ALL the subsequent (encrypted) ciphertext. "PCBC" mode, on encryption, "xors" both the cleartext of block N and the ciphertext resulting from block N with the cleartext for block N+1 prior to encrypting block N+1. .PP .nf .B unsigned long cbc_cksum(input, output, length, schedule, ivec) .B C_Block *input; .B C_Block *output; .B long length; .B Key_schedule schedule; .B C_Block *ivec; .fi .PP .I cbc_cksum produces an 8 byte cryptographic checksum by cipher-block-chain encrypting the cleartext data pointed to by the .I input argument. All of the ciphertext output is discarded, except the last 8-byte ciphertext block, which is written into the area pointed to by the .I output argument. It uses the key schedule, provided by the .I schedule argument and initialization vector provided by the .I ivec argument. If the .I length argument is not an integral multiple of eight bytes, the last cleartext block is copied to a temp and zero filled (highest addresses). The output is ALWAYS eight bytes. .PP The routine also returns an unsigned long, which is the last (highest address) half of the 8 byte checksum computed. .PP .nf .B unsigned long quad_cksum(input, output, length, out_count, seed) .B C_Block *input; .B C_Block *output; .B long length; .B int out_count; .B C_BLOCK *seed; .fi .PP .I quad_cksum produces a checksum by chaining quadratic operations on the cleartext data pointed to by the .I input argument. The .I length argument specifies the length of the input -- only exactly that many bytes are included for the checksum, without any padding. .PP The algorithm may be iterated over the same input data, if the .I out_count argument is 2, 3 or 4, and the optional .I output argument is a non-null pointer . The default is one iteration, and it will not run more than 4 times. Multiple iterations run slower, but provide a longer checksum if desired. The .I seed argument provides an 8-byte seed for the first iteration. If multiple iterations are requested, the results of one iteration are automatically used as the seed for the next iteration. .PP It returns both an unsigned long checksum value, and if the .I output argument is not a null pointer, up to 16 bytes of the computed checksum are written into the output. .PP .PP .SH FILES /usr/include/des.h .br /usr/lib/libdes.a .SH "SEE ALSO" .SH DIAGNOSTICS .SH BUGS This software has not yet been compiled or tested on machines other than the VAX and the IBM PC. .SH AUTHORS Steve Miller, MIT Project Athena/Digital Equipment Corporation .SH RESTRICTIONS COPYRIGHT 1985, 1986 Massachusetts Institute of Technology .PP This software may not be exported outside of the US without a special license from the US Dept of Commerce. It may be replaced by any secret key block cipher with block length and key length of 8 bytes, as long as the interface is the same as described here.