2 * Copyright (c) 2000-2002,2005,2008 by Solar Designer. See LICENSE.
14 * We separate words in the generated "passphrases" with random special
15 * characters out of a set of 8 (so we encode 3 bits per separator
16 * character). To enable the use of our "passphrases" within FTP URLs
17 * (and similar), we pick characters that are defined by RFC 3986 as
18 * being safe within "userinfo" part of URLs without encoding and
19 * without having a special meaning. Out of those, we avoid characters
20 * that are visually ambiguous or difficult over the phone. This
21 * happens to leave us with exactly 8 characters.
23 #define SEPARATORS "-_!$&*+="
25 static int read_loop(int fd
, unsigned char *buffer
, int count
)
31 block
= read(fd
, &buffer
[offset
], count
);
34 if (errno
== EINTR
) continue;
37 if (!block
) return offset
;
46 char *_passwdqc_random(passwdqc_params_t
*params
)
48 static char output
[0x100];
50 int use_separators
, count
, i
;
51 unsigned int length
, extra
;
54 unsigned char bytes
[2];
56 bits
= params
->random_bits
;
57 if (bits
< 24 || bits
> 128)
60 count
= 1 + (bits
+ (14 - 12)) / 15;
61 use_separators
= ((bits
+ 11) / 12 != count
);
63 length
= count
* 7 - 1;
64 if (length
>= sizeof(output
) || (int)length
> params
->max
)
67 if ((fd
= open("/dev/urandom", O_RDONLY
)) < 0) return NULL
;
71 if (read_loop(fd
, bytes
, sizeof(bytes
)) != sizeof(bytes
)) {
76 i
= (((int)bytes
[1] & 0x0f) << 8) | (int)bytes
[0];
77 start
= _passwdqc_wordset_4k
[i
];
78 end
= memchr(start
, '\0', 6);
79 if (!end
) end
= start
+ 6;
81 if (length
+ extra
>= sizeof(output
) - 1) {
85 memcpy(&output
[length
], start
, extra
);
89 if (use_separators
&& bits
> 3) {
90 i
= ((int)bytes
[1] & 0x70) >> 4;
91 output
[length
++] = SEPARATORS
[i
];
95 output
[length
++] = ' ';
98 memset(bytes
, 0, sizeof(bytes
));
99 output
[length
] = '\0';