aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-11-10 18:52:35 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-11-10 18:52:35 +0000
commit2211d5268cc6fc5575f758a9835070fae5ffc405 (patch)
tree46b23253b2be2c2c5bcdb6909a740e894a93ae07
parent56dceb9b7722193ef53fb1afb981f1289eecb0b0 (diff)
downloadbusybox-w32-2211d5268cc6fc5575f758a9835070fae5ffc405.tar.gz
busybox-w32-2211d5268cc6fc5575f758a9835070fae5ffc405.tar.bz2
busybox-w32-2211d5268cc6fc5575f758a9835070fae5ffc405.zip
libbb: add optionl support for SHA256/512 encrypted passwords
function old new delta sha_crypt - 2423 +2423 cryptpw_main 128 183 +55 to64 - 29 +29 pw_encrypt 974 1000 +26 str_rounds - 11 +11 login_main 1532 1541 +9 packed_usage 25215 25200 -15 __md5_to64 29 - -29 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 3/1 up/down: 2553/-44) Total: 2509 bytes
-rw-r--r--coreutils/Kbuild2
-rw-r--r--include/usage.h5
-rw-r--r--libbb/pw_encrypt.c43
-rw-r--r--libbb/pw_encrypt_md5.c14
-rw-r--r--libbb/pw_encrypt_sha.c251
-rw-r--r--loginutils/Config.in14
-rw-r--r--loginutils/cryptpw.c28
7 files changed, 322 insertions, 35 deletions
diff --git a/coreutils/Kbuild b/coreutils/Kbuild
index a5a2d4c26..67c56588a 100644
--- a/coreutils/Kbuild
+++ b/coreutils/Kbuild
@@ -62,6 +62,8 @@ lib-$(CONFIG_RM) += rm.o
62lib-$(CONFIG_RMDIR) += rmdir.o 62lib-$(CONFIG_RMDIR) += rmdir.o
63lib-$(CONFIG_SEQ) += seq.o 63lib-$(CONFIG_SEQ) += seq.o
64lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o 64lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o
65lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o
66lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o
65lib-$(CONFIG_SLEEP) += sleep.o 67lib-$(CONFIG_SLEEP) += sleep.o
66lib-$(CONFIG_SPLIT) += split.o 68lib-$(CONFIG_SPLIT) += split.o
67lib-$(CONFIG_SORT) += sort.o 69lib-$(CONFIG_SORT) += sort.o
diff --git a/include/usage.h b/include/usage.h
index 75b44a25b..71f221828 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -557,8 +557,13 @@
557 "\n -r Delete crontab" \ 557 "\n -r Delete crontab" \
558 "\n FILE Replace crontab by FILE ('-': stdin)" \ 558 "\n FILE Replace crontab by FILE ('-': stdin)" \
559 559
560#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
561#define cryptpw_trivial_usage \
562 "[-a des|md5|sha256/512] [string]"
563#else
560#define cryptpw_trivial_usage \ 564#define cryptpw_trivial_usage \
561 "[-a des|md5] [string]" 565 "[-a des|md5] [string]"
566#endif
562#define cryptpw_full_usage "\n\n" \ 567#define cryptpw_full_usage "\n\n" \
563 "Output crypted string.\n" \ 568 "Output crypted string.\n" \
564 "If string isn't supplied on cmdline, read it from stdin.\n" \ 569 "If string isn't supplied on cmdline, read it from stdin.\n" \
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 0b826f48d..572591ea9 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -15,16 +15,27 @@
15 * DES and MD5 crypt implementations are taken from uclibc. 15 * DES and MD5 crypt implementations are taken from uclibc.
16 * They were modified to not use static buffers. 16 * They were modified to not use static buffers.
17 */ 17 */
18/* Common for them */ 18
19/* Used by pw_encrypt_XXX.c */
19static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 20static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
21static char*
22to64(char *s, unsigned v, int n)
23{
24 while (--n >= 0) {
25 *s++ = ascii64[v & 0x3f];
26 v >>= 6;
27 }
28 return s;
29}
30
20#include "pw_encrypt_des.c" 31#include "pw_encrypt_des.c"
21#include "pw_encrypt_md5.c" 32#include "pw_encrypt_md5.c"
33#if ENABLE_USE_BB_CRYPT_SHA
34#include "pw_encrypt_sha.c"
35#endif
22 36
23/* Other advanced crypt ids: */ 37/* Other advanced crypt ids (TODO?): */
24/* $2$ or $2a$: Blowfish */ 38/* $2$ or $2a$: Blowfish */
25/* $5$: SHA-256 */
26/* $6$: SHA-512 */
27/* TODO: implement SHA - http://people.redhat.com/drepper/SHA-crypt.txt */
28 39
29static struct const_des_ctx *des_cctx; 40static struct const_des_ctx *des_cctx;
30static struct des_ctx *des_ctx; 41static struct des_ctx *des_ctx;
@@ -32,18 +43,20 @@ static struct des_ctx *des_ctx;
32/* my_crypt returns malloc'ed data */ 43/* my_crypt returns malloc'ed data */
33static char *my_crypt(const char *key, const char *salt) 44static char *my_crypt(const char *key, const char *salt)
34{ 45{
35 /* First, check if we are supposed to be using the MD5 replacement 46 /* MD5 or SHA? */
36 * instead of DES... */ 47 if (salt[0] == '$' && salt[1] && salt[2] == '$') {
37 if (salt[0] == '$' && salt[1] == '1' && salt[2] == '$') { 48 if (salt[1] == '1')
38 return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); 49 return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
50#if ENABLE_USE_BB_CRYPT_SHA
51 if (salt[1] == '5' || salt[1] == '6')
52 return sha_crypt((char*)key, (char*)salt);
53#endif
39 } 54 }
40 55
41 { 56 if (!des_cctx)
42 if (!des_cctx) 57 des_cctx = const_des_init();
43 des_cctx = const_des_init(); 58 des_ctx = des_init(des_ctx, des_cctx);
44 des_ctx = des_init(des_ctx, des_cctx); 59 return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
45 return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
46 }
47} 60}
48 61
49/* So far nobody wants to have it public */ 62/* So far nobody wants to have it public */
diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c
index 8d0a516cf..b7478aa9d 100644
--- a/libbb/pw_encrypt_md5.c
+++ b/libbb/pw_encrypt_md5.c
@@ -494,16 +494,6 @@ static void __md5_Transform(uint32_t state[4], const unsigned char block[64])
494} 494}
495 495
496 496
497static char*
498__md5_to64(char *s, unsigned v, int n)
499{
500 while (--n >= 0) {
501 *s++ = ascii64[v & 0x3f];
502 v >>= 6;
503 }
504 return s;
505}
506
507/* 497/*
508 * UNIX password 498 * UNIX password
509 * 499 *
@@ -605,9 +595,9 @@ md5_crypt(char passwd[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
605 final[16] = final[5]; 595 final[16] = final[5];
606 for (i = 0; i < 5; i++) { 596 for (i = 0; i < 5; i++) {
607 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; 597 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
608 p = __md5_to64(p, l, 4); 598 p = to64(p, l, 4);
609 } 599 }
610 p = __md5_to64(p, final[11], 2); 600 p = to64(p, final[11], 2);
611 *p = '\0'; 601 *p = '\0';
612 602
613 /* Don't leave anything around in vm they could use. */ 603 /* Don't leave anything around in vm they could use. */
diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c
new file mode 100644
index 000000000..9acbabb3b
--- /dev/null
+++ b/libbb/pw_encrypt_sha.c
@@ -0,0 +1,251 @@
1/* SHA256 and SHA512-based Unix crypt implementation.
2 * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
3 */
4
5/* Prefix for optional rounds specification. */
6static const char str_rounds[] = "rounds=%u$";
7
8/* Maximum salt string length. */
9#define SALT_LEN_MAX 16
10/* Default number of rounds if not explicitly specified. */
11#define ROUNDS_DEFAULT 5000
12/* Minimum number of rounds. */
13#define ROUNDS_MIN 1000
14/* Maximum number of rounds. */
15#define ROUNDS_MAX 999999999
16
17static char *
18NOINLINE
19sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
20{
21 void (*sha_begin)(void *ctx) FAST_FUNC;
22 void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC;
23 void* (*sha_end)(void *resbuf, void *ctx) FAST_FUNC;
24 int _32or64;
25
26 char *result, *resptr;
27
28 /* btw, sha256 needs [32] and uint32_t only */
29 unsigned char alt_result[64] __attribute__((__aligned__(__alignof__(uint64_t))));
30 unsigned char temp_result[64] __attribute__((__aligned__(__alignof__(uint64_t))));
31 union {
32 sha256_ctx_t x;
33 sha512_ctx_t y;
34 } ctx;
35 union {
36 sha256_ctx_t x;
37 sha512_ctx_t y;
38 } alt_ctx;
39 unsigned salt_len;
40 unsigned key_len;
41 unsigned cnt;
42 unsigned rounds;
43 char *cp;
44 char is_sha512;
45
46 /* Analyze salt, construct already known part of result */
47 cnt = strlen(salt_data) + 1 + 43 + 1;
48 is_sha512 = salt_data[1];
49 if (is_sha512 == '6')
50 cnt += 43;
51 result = resptr = xzalloc(cnt); /* will provide NUL terminator */
52 *resptr++ = '$';
53 *resptr++ = is_sha512;
54 *resptr++ = '$';
55 rounds = ROUNDS_DEFAULT;
56 salt_data += 3;
57 if (strncmp(salt_data, str_rounds, 7) == 0) {
58 /* 7 == strlen("rounds=") */
59 char *endp;
60 unsigned srounds = bb_strtou(salt_data + 7, &endp, 10);
61 if (*endp == '$') {
62 salt_data = endp + 1;
63 rounds = srounds;
64 if (rounds < ROUNDS_MIN)
65 rounds = ROUNDS_MIN;
66 if (rounds > ROUNDS_MAX)
67 rounds = ROUNDS_MAX;
68 }
69 }
70 salt_len = strchrnul(salt_data, '$') - salt_data;
71 if (salt_len > SALT_LEN_MAX)
72 salt_len = SALT_LEN_MAX;
73 /* xstrdup assures suitable alignment; also we will use it
74 as a scratch space later. */
75 salt_data = xstrndup(salt_data, salt_len);
76 if (rounds != ROUNDS_DEFAULT) /* add "rounds=NNNNN$" */
77 resptr += sprintf(resptr, str_rounds, rounds);
78 strcpy(resptr, salt_data);
79 resptr += salt_len;
80 *resptr++ = '$';
81 /* key data doesn't need much processing */
82 key_len = strlen(key_data);
83 key_data = xstrdup(key_data);
84
85 /* Which flavor of SHAnnn ops to use? */
86 sha_begin = (void*)sha256_begin;
87 sha_hash = (void*)sha256_hash;
88 sha_end = (void*)sha256_end;
89 _32or64 = 32;
90 if (is_sha512 == '6') {
91 sha_begin = (void*)sha512_begin;
92 sha_hash = (void*)sha512_hash;
93 sha_end = (void*)sha512_end;
94 _32or64 = 64;
95 }
96
97 /* Add KEY, SALT. */
98 sha_begin(&ctx);
99 sha_hash(key_data, key_len, &ctx);
100 sha_hash(salt_data, salt_len, &ctx);
101
102 /* Compute alternate SHA sum with input KEY, SALT, and KEY.
103 The final result will be added to the first context. */
104 sha_begin(&alt_ctx);
105 sha_hash(key_data, key_len, &alt_ctx);
106 sha_hash(salt_data, salt_len, &alt_ctx);
107 sha_hash(key_data, key_len, &alt_ctx);
108 sha_end(alt_result, &alt_ctx);
109
110 /* Add result of this to the other context. */
111 /* Add for any character in the key one byte of the alternate sum. */
112 for (cnt = key_len; cnt > _32or64; cnt -= _32or64)
113 sha_hash(alt_result, _32or64, &ctx);
114 sha_hash(alt_result, cnt, &ctx);
115
116 /* Take the binary representation of the length of the key and for every
117 1 add the alternate sum, for every 0 the key. */
118 for (cnt = key_len; cnt != 0; cnt >>= 1)
119 if ((cnt & 1) != 0)
120 sha_hash(alt_result, _32or64, &ctx);
121 else
122 sha_hash(key_data, key_len, &ctx);
123
124 /* Create intermediate result. */
125 sha_end(alt_result, &ctx);
126
127 /* Start computation of P byte sequence. */
128 /* For every character in the password add the entire password. */
129 sha_begin(&alt_ctx);
130 for (cnt = 0; cnt < key_len; ++cnt)
131 sha_hash(key_data, key_len, &alt_ctx);
132 sha_end(temp_result, &alt_ctx);
133
134 /* NB: past this point, raw key_data is not used anymore */
135
136 /* Create byte sequence P. */
137#define p_bytes key_data /* reuse the buffer as it is of the key_len size */
138 cp = p_bytes; /* was: ... = alloca(key_len); */
139 for (cnt = key_len; cnt >= _32or64; cnt -= _32or64) {
140 cp = memcpy(cp, temp_result, _32or64);
141 cp += _32or64;
142 }
143 memcpy(cp, temp_result, cnt);
144
145 /* Start computation of S byte sequence. */
146 /* For every character in the password add the entire password. */
147 sha_begin(&alt_ctx);
148 for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
149 sha_hash(salt_data, salt_len, &alt_ctx);
150 sha_end(temp_result, &alt_ctx);
151
152 /* NB: past this point, raw salt_data is not used anymore */
153
154 /* Create byte sequence S. */
155#define s_bytes salt_data /* reuse the buffer as it is of the salt_len size */
156 cp = s_bytes; /* was: ... = alloca(salt_len); */
157 for (cnt = salt_len; cnt >= _32or64; cnt -= _32or64) {
158 cp = memcpy(cp, temp_result, _32or64);
159 cp += _32or64;
160 }
161 memcpy(cp, temp_result, cnt);
162
163 /* Repeatedly run the collected hash value through SHA to burn
164 CPU cycles. */
165 for (cnt = 0; cnt < rounds; ++cnt) {
166 sha_begin(&ctx);
167
168 /* Add key or last result. */
169 if ((cnt & 1) != 0)
170 sha_hash(p_bytes, key_len, &ctx);
171 else
172 sha_hash(alt_result, _32or64, &ctx);
173 /* Add salt for numbers not divisible by 3. */
174 if (cnt % 3 != 0)
175 sha_hash(s_bytes, salt_len, &ctx);
176 /* Add key for numbers not divisible by 7. */
177 if (cnt % 7 != 0)
178 sha_hash(p_bytes, key_len, &ctx);
179 /* Add key or last result. */
180 if ((cnt & 1) != 0)
181 sha_hash(alt_result, _32or64, &ctx);
182 else
183 sha_hash(p_bytes, key_len, &ctx);
184
185 sha_end(alt_result, &ctx);
186 }
187
188
189 /* Append encrypted password to result buffer */
190//TODO: replace with something like
191// bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64);
192#define b64_from_24bit(B2, B1, B0, N) \
193do { \
194 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
195 resptr = to64(resptr, w, N); \
196} while (0)
197 if (is_sha512 == '5') {
198 b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4);
199 b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4);
200 b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4);
201 b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4);
202 b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4);
203 b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4);
204 b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4);
205 b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4);
206 b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4);
207 b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4);
208 b64_from_24bit(0, alt_result[31], alt_result[30], 3);
209 } else {
210 b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4);
211 b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4);
212 b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4);
213 b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4);
214 b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4);
215 b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4);
216 b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4);
217 b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4);
218 b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4);
219 b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4);
220 b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4);
221 b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4);
222 b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4);
223 b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4);
224 b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4);
225 b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4);
226 b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4);
227 b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4);
228 b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4);
229 b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4);
230 b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4);
231 b64_from_24bit(0, 0, alt_result[63], 2);
232 }
233 /* *resptr = '\0'; - xzalloc did it */
234#undef b64_from_24bit
235
236 /* Clear the buffer for the intermediate result so that people
237 attaching to processes or reading core dumps cannot get any
238 information. */
239 memset(temp_result, 0, sizeof(temp_result));
240 memset(alt_result, 0, sizeof(alt_result));
241 memset(&ctx, 0, sizeof(ctx));
242 memset(&alt_ctx, 0, sizeof(alt_ctx));
243 memset(key_data, 0, key_len); /* also p_bytes */
244 memset(salt_data, 0, salt_len); /* also s_bytes */
245 free(key_data);
246 free(salt_data);
247#undef p_bytes
248#undef s_bytes
249
250 return result;
251}
diff --git a/loginutils/Config.in b/loginutils/Config.in
index bb1369cdd..5f66e8685 100644
--- a/loginutils/Config.in
+++ b/loginutils/Config.in
@@ -58,7 +58,7 @@ config USE_BB_SHADOW
58 password servers and whatnot. 58 password servers and whatnot.
59 59
60config USE_BB_CRYPT 60config USE_BB_CRYPT
61 bool "Use internal DES and MD5 crypt functions" 61 bool "Use internal crypt functions"
62 default y 62 default y
63 help 63 help
64 Busybox has internal DES and MD5 crypt functions. 64 Busybox has internal DES and MD5 crypt functions.
@@ -79,6 +79,18 @@ config USE_BB_CRYPT
79 In static build, it makes code _smaller_ by about 1.2k, 79 In static build, it makes code _smaller_ by about 1.2k,
80 and likely many kilobytes less of bss. 80 and likely many kilobytes less of bss.
81 81
82config USE_BB_CRYPT_SHA
83 bool "Enable SHA256/512 crypt functions"
84 default n
85 depends on USE_BB_CRYPT
86 help
87 Enable this if you have passwords starting with "$5$" or "$6$"
88 in your /etc/passwd or /etc/shadow files. These passwords
89 are hashed using SHA256 and SHA512 algorithms. Support for them
90 was added to glibc in 2008.
91 With this option off, login will fail password check for any
92 user which has password encrypted with these algorithms.
93
82config ADDGROUP 94config ADDGROUP
83 bool "addgroup" 95 bool "addgroup"
84 default n 96 default n
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c
index db5d95920..d76deac20 100644
--- a/loginutils/cryptpw.c
+++ b/loginutils/cryptpw.c
@@ -34,22 +34,36 @@ done
34int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 34int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
35int cryptpw_main(int argc UNUSED_PARAM, char **argv) 35int cryptpw_main(int argc UNUSED_PARAM, char **argv)
36{ 36{
37 char salt[sizeof("$N$XXXXXXXX")]; 37 char salt[sizeof("$N$") + 16];
38 char *opt_a; 38 char *opt_a;
39 int opts;
39 40
40 if (!getopt32(argv, "a:", &opt_a) || opt_a[0] != 'd') { 41 opts = getopt32(argv, "a:", &opt_a);
42
43 if (opts && opt_a[0] == 'd') {
44 crypt_make_salt(salt, 2/2, 0); /* des */
45#if TESTING
46 strcpy(salt, "a.");
47#endif
48 } else {
41 salt[0] = '$'; 49 salt[0] = '$';
42 salt[1] = '1'; 50 salt[1] = '1';
43 salt[2] = '$'; 51 salt[2] = '$';
44 crypt_make_salt(salt + 3, 4, 0); /* md5 */ 52#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
53 if (opts && opt_a[0] == 's') {
54 salt[1] = '5' + (strcmp(opt_a, "sha512") == 0);
55 crypt_make_salt(salt + 3, 16/2, 0); /* sha */
45#if TESTING 56#if TESTING
46 strcpy(salt + 3, "ajg./bcf"); 57 strcpy(salt, "$6$em7yVj./Mv5n1V5X");
47#endif 58#endif
48 } else { 59 } else
49 crypt_make_salt(salt, 1, 0); /* des */ 60#endif
61 {
62 crypt_make_salt(salt + 3, 8/2, 0); /* md5 */
50#if TESTING 63#if TESTING
51 strcpy(salt, "a."); 64 strcpy(salt + 3, "ajg./bcf");
52#endif 65#endif
66 }
53 } 67 }
54 68
55 puts(pw_encrypt(argv[optind] ? argv[optind] : xmalloc_fgetline(stdin), salt, 1)); 69 puts(pw_encrypt(argv[optind] ? argv[optind] : xmalloc_fgetline(stdin), salt, 1));