]> granicus.if.org Git - linux-pam/blob - modules/pam_pwdb/bigcrypt.-c
Relevant BUGIDs: 812567
[linux-pam] / modules / pam_pwdb / bigcrypt.-c
1 /*
2  * This function implements the "bigcrypt" algorithm specifically for
3  * Linux-PAM.
4  *  
5  * This algorithm is algorithm 0 (default) shipped with the C2 secure
6  * implementation of Digital UNIX.
7  * 
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.
12  * 
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.
17  * 
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();
23  *
24  * Andy Phillips <atp@mssl.ucl.ac.uk>
25  */
26
27 /*
28  * Max cleartext password length in segments of 8 characters this
29  * function can deal with (16 segments of 8 chars= max 128 character
30  * password).
31  */
32   
33 #define MAX_PASS_LEN       16
34 #define SEGMENT_SIZE       8
35 #define SALT_SIZE          2
36 #define KEYBUF_SIZE        ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE)
37 #define ESEGMENT_SIZE      11
38 #define CBUF_SIZE          ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1)
39
40 static char *bigcrypt(const char *key, const char *salt)
41 {
42     static char dec_c2_cryptbuf[CBUF_SIZE];        /* static storage area */
43
44     unsigned long int keylen,n_seg,j;
45     char *cipher_ptr,*plaintext_ptr,*tmp_ptr,*salt_ptr;
46     char keybuf[KEYBUF_SIZE+1];
47
48     D(("called with key='%s', salt='%s'.", key, salt));
49
50     /* reset arrays */
51     memset(keybuf, 0, KEYBUF_SIZE+1);
52     memset(dec_c2_cryptbuf, 0, CBUF_SIZE);
53
54     /* fill KEYBUF_SIZE with key */
55     strncpy(keybuf, key, KEYBUF_SIZE);
56
57     /* deal with case that we are doing a password check for a
58        conventially encrypted password: the salt will be
59        SALT_SIZE+ESEGMENT_SIZE long. */
60     if (strlen(salt) == (SALT_SIZE+ESEGMENT_SIZE))
61         keybuf[SEGMENT_SIZE] = '\0';       /* terminate password early(?) */
62
63     keylen = strlen(keybuf);
64
65     if (!keylen) {
66         n_seg = 1;
67     } else {
68         /* work out how many segments */
69         n_seg = 1 + ((keylen-1)/SEGMENT_SIZE);
70     }
71
72     if (n_seg > MAX_PASS_LEN)
73         n_seg = MAX_PASS_LEN; /* truncate at max length */
74
75     /* set up some pointers */
76     cipher_ptr = dec_c2_cryptbuf;
77     plaintext_ptr = keybuf;
78
79     /* do the first block with supplied salt */
80     tmp_ptr = crypt(plaintext_ptr,salt);                  /* libc crypt() */
81
82     /* and place in the static area */
83     strncpy(cipher_ptr, tmp_ptr, 13);
84     cipher_ptr += ESEGMENT_SIZE + SALT_SIZE;
85     plaintext_ptr += SEGMENT_SIZE;         /* first block of SEGMENT_SIZE */
86
87     /* change the salt (1st 2 chars of previous block) - this was found
88        by dowsing */
89
90     salt_ptr = cipher_ptr - ESEGMENT_SIZE;
91
92     /* so far this is identical to "return crypt(key, salt);", if
93        there is more than one block encrypt them... */
94
95     if (n_seg > 1) {
96         for (j=2; j <= n_seg; j++) {
97
98             tmp_ptr = crypt(plaintext_ptr, salt_ptr);
99
100             /* skip the salt for seg!=0 */
101             strncpy(cipher_ptr, (tmp_ptr+SALT_SIZE), ESEGMENT_SIZE);
102
103             cipher_ptr += ESEGMENT_SIZE; 
104             plaintext_ptr += SEGMENT_SIZE;
105             salt_ptr = cipher_ptr - ESEGMENT_SIZE;
106         }
107     }
108
109     D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf));
110
111     /* this is the <NUL> terminated encrypted password */
112
113     return dec_c2_cryptbuf;
114 }