2 * This function implements the "bigcrypt" algorithm specifically for
5 * This algorithm is algorithm 0 (default) shipped with the C2 secure
6 * implementation of Digital UNIX.
8 * Disclaimer: This work is not based on the source code to Digital
9 * UNIX, nor am I connected to Digital Equipment Corp, in any way
10 * other than as a customer. This code is based on published
11 * interfaces and reasonable guesswork.
13 * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8
14 * characters or less. Each block is encrypted using the standard UNIX
15 * libc crypt function. The result of the encryption for one block
16 * provides the salt for the suceeding block.
18 * Restrictions: The buffer used to hold the encrypted result is
19 * statically allocated. (see MAX_PASS_LEN below). This is necessary,
20 * as the returned pointer points to "static data that are overwritten
21 * by each call", (XPG3: XSI System Interface + Headers pg 109), and
22 * this is a drop in replacement for crypt();
24 * Andy Phillips <atp@mssl.ucl.ac.uk>
29 #include <security/_pam_macros.h>
31 char *crypt(const char *key, const char *salt);
32 char *bigcrypt(const char *key, const char *salt);
35 * Max cleartext password length in segments of 8 characters this
36 * function can deal with (16 segments of 8 chars= max 128 character
40 #define MAX_PASS_LEN 16
41 #define SEGMENT_SIZE 8
43 #define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE)
44 #define ESEGMENT_SIZE 11
45 #define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1)
47 char *bigcrypt(const char *key, const char *salt)
49 char *dec_c2_cryptbuf;
51 unsigned long int keylen, n_seg, j;
52 char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr;
53 char keybuf[KEYBUF_SIZE + 1];
55 D(("called with key='%s', salt='%s'.", key, salt));
58 dec_c2_cryptbuf = malloc(CBUF_SIZE);
59 if (!dec_c2_cryptbuf) {
62 memset(keybuf, 0, KEYBUF_SIZE + 1);
63 memset(dec_c2_cryptbuf, 0, CBUF_SIZE);
65 /* fill KEYBUF_SIZE with key */
66 strncpy(keybuf, key, KEYBUF_SIZE);
68 /* deal with case that we are doing a password check for a
69 conventially encrypted password: the salt will be
70 SALT_SIZE+ESEGMENT_SIZE long. */
71 if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE))
72 keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */
74 keylen = strlen(keybuf);
79 /* work out how many segments */
80 n_seg = 1 + ((keylen - 1) / SEGMENT_SIZE);
83 if (n_seg > MAX_PASS_LEN)
84 n_seg = MAX_PASS_LEN; /* truncate at max length */
86 /* set up some pointers */
87 cipher_ptr = dec_c2_cryptbuf;
88 plaintext_ptr = keybuf;
90 /* do the first block with supplied salt */
91 tmp_ptr = crypt(plaintext_ptr, salt); /* libc crypt() */
93 /* and place in the static area */
94 strncpy(cipher_ptr, tmp_ptr, 13);
95 cipher_ptr += ESEGMENT_SIZE + SALT_SIZE;
96 plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */
98 /* change the salt (1st 2 chars of previous block) - this was found
101 salt_ptr = cipher_ptr - ESEGMENT_SIZE;
103 /* so far this is identical to "return crypt(key, salt);", if
104 there is more than one block encrypt them... */
107 for (j = 2; j <= n_seg; j++) {
109 tmp_ptr = crypt(plaintext_ptr, salt_ptr);
111 /* skip the salt for seg!=0 */
112 strncpy(cipher_ptr, (tmp_ptr + SALT_SIZE), ESEGMENT_SIZE);
114 cipher_ptr += ESEGMENT_SIZE;
115 plaintext_ptr += SEGMENT_SIZE;
116 salt_ptr = cipher_ptr - ESEGMENT_SIZE;
119 D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf));
121 /* this is the <NUL> terminated encrypted password */
123 return dec_c2_cryptbuf;