1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
/*
* This function implements the "bigcrypt" algorithm specifically for
* Linux-PAM.
*
* This algorithm is algorithm 0 (default) shipped with the C2 secure
* implementation of Digital UNIX.
*
* Disclaimer: This work is not based on the source code to Digital
* UNIX, nor am I connected to Digital Equipment Corp, in any way
* other than as a customer. This code is based on published
* interfaces and reasonable guesswork.
*
* Description: The cleartext is divided into blocks of SEGMENT_SIZE=8
* characters or less. Each block is encrypted using the standard UNIX
* libc crypt function. The result of the encryption for one block
* provides the salt for the suceeding block.
*
* Restrictions: The buffer used to hold the encrypted result is
* statically allocated. (see MAX_PASS_LEN below). This is necessary,
* as the returned pointer points to "static data that are overwritten
* by each call", (XPG3: XSI System Interface + Headers pg 109), and
* this is a drop in replacement for crypt();
*
* Andy Phillips <atp@mssl.ucl.ac.uk>
*/
#define _XOPEN_SOURCE 700
#include <unistd.h>
#include <string.h>
#include "bigcrypt.h"
/*
* Max cleartext password length in segments of 8 characters this
* function can deal with (16 segments of 8 chars= max 128 character
* password).
*/
#define MAX_SEGMENTS 16
#define SEGMENT_SIZE 8
#define SALT_SIZE 2
#define ESEGMENT_SIZE 11
char *bigcrypt(char const * key, char const * salt) {
static char outbuf[MAX_SEGMENTS * ESEGMENT_SIZE + SALT_SIZE + 1]; /* static storage area */
unsigned char n_seg, seg;
char * outptr;
/* ensure NUL-termination */
memset(outbuf, 0, sizeof(outbuf));
if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE)) /* conventional crypt */
n_seg = 1;
else if (key[0] == '\0')
n_seg = 1;
else
n_seg = (strnlen(key, MAX_SEGMENTS * SEGMENT_SIZE) + SEGMENT_SIZE - 1) / SEGMENT_SIZE;
/* first block is special and just traditional crypt() */
outptr = outbuf;
strncpy(outptr, crypt(key, salt), SALT_SIZE + ESEGMENT_SIZE);
for (seg = 1, outptr += SALT_SIZE; seg < n_seg; ++seg) {
/* subsequent blocks use the previous output block for salt input */
salt = outptr;
key += SEGMENT_SIZE;
outptr += ESEGMENT_SIZE;
/* and omit the salt on output */
strncpy(outptr, crypt(key, salt) + SALT_SIZE, ESEGMENT_SIZE);
}
return outbuf;
}
|