Annotation of src/usr.bin/encrypt/encrypt.c, Revision 1.30
1.30 ! deraadt 1: /* $OpenBSD: encrypt.c,v 1.29 2013/05/23 01:33:08 tedu Exp $ */
1.1 downsj 2:
3: /*
4: * Copyright (c) 1996, Jason Downs. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27:
28: #include <sys/types.h>
1.15 millert 29: #include <ctype.h>
1.1 downsj 30: #include <err.h>
1.3 downsj 31: #include <errno.h>
1.15 millert 32: #include <pwd.h>
33: #include <stdio.h>
1.7 kstailey 34: #include <stdlib.h>
1.1 downsj 35: #include <string.h>
36: #include <unistd.h>
1.14 millert 37: #include <login_cap.h>
1.27 jdixon 38: #include <limits.h>
1.1 downsj 39:
40: /*
41: * Very simple little program, for encrypting passwords from the command
42: * line. Useful for scripts and such.
43: */
44:
1.5 provos 45: #define DO_MAKEKEY 0
46: #define DO_DES 1
47: #define DO_MD5 2
48: #define DO_BLF 3
49:
1.15 millert 50: extern char *__progname;
1.5 provos 51: char buffer[_PASSWORD_LEN];
1.19 deraadt 52:
53: void usage(void);
1.30 ! deraadt 54: int ideal_rounds(void);
1.19 deraadt 55: void print_passwd(char *, int, void *);
1.3 downsj 56:
1.15 millert 57: void
58: usage(void)
1.1 downsj 59: {
1.15 millert 60:
61: (void)fprintf(stderr,
1.25 jmc 62: "usage: %s [-km] [-b rounds] [-c class] [-p | string] [-s salt]\n",
1.15 millert 63: __progname);
64: exit(1);
1.1 downsj 65: }
66:
1.29 tedu 67: /*
68: * Time how long 8 rounds takes to measure this system's performance.
69: * We are aiming for something that takes between 0.25 and 0.5 seconds.
70: */
71: int
1.30 ! deraadt 72: ideal_rounds(void)
1.29 tedu 73: {
74: clock_t before, after;
75: int r = 8;
76: char buf[_PASSWORD_LEN];
77: int duration;
78:
79: strlcpy(buf, bcrypt_gensalt(r), _PASSWORD_LEN);
80: before = clock();
81: crypt("testpassword", buf);
82: after = clock();
83:
84: duration = after - before;
85:
86: /* too quick? slow it down. */
87: while (duration <= CLOCKS_PER_SEC / 4) {
88: r += 1;
89: duration *= 2;
90: }
91: /* too slow? speed it up. */
92: while (duration > CLOCKS_PER_SEC / 2) {
93: r -= 1;
94: duration /= 2;
95: }
96:
97: return r;
98: }
99:
100:
1.15 millert 101: void
102: print_passwd(char *string, int operation, void *extra)
1.5 provos 103: {
1.23 moritz 104: char msalt[3], *salt, *cryptstr;
1.15 millert 105: login_cap_t *lc;
1.21 millert 106: int pwd_gensalt(char *, int, login_cap_t *, char);
1.22 deraadt 107: void to64(char *, u_int32_t, int n);
1.15 millert 108:
109: switch(operation) {
110: case DO_MAKEKEY:
111: /*
112: * makekey mode: parse string into separate DES key and salt.
113: */
114: if (strlen(string) != 10) {
115: /* To be compatible... */
116: errx(1, "%s", strerror(EFTYPE));
117: }
1.17 deraadt 118: strlcpy(msalt, &string[8], sizeof msalt);
1.15 millert 119: salt = msalt;
120: break;
121:
122: case DO_MD5:
1.17 deraadt 123: strlcpy(buffer, "$1$", sizeof buffer);
1.15 millert 124: to64(&buffer[3], arc4random(), 4);
125: to64(&buffer[7], arc4random(), 4);
1.17 deraadt 126: strlcpy(buffer + 11, "$", sizeof buffer - 11);
1.15 millert 127: salt = buffer;
128: break;
129:
130: case DO_BLF:
131: strlcpy(buffer, bcrypt_gensalt(*(int *)extra), _PASSWORD_LEN);
132: salt = buffer;
133: break;
134:
135: case DO_DES:
136: salt = extra;
137: break;
138:
139: default:
1.18 millert 140: if ((lc = login_getclass(extra)) == NULL)
141: errx(1, "unable to get login class `%s'",
142: extra ? (char *)extra : "default");
1.21 millert 143: if (!pwd_gensalt(buffer, _PASSWORD_LEN, lc, 'l'))
1.15 millert 144: errx(1, "can't generate salt");
145: salt = buffer;
146: break;
147: }
148:
1.23 moritz 149: if ((cryptstr = crypt(string, salt)) == NULL)
150: errx(1, "crypt failed");
151: fputs(cryptstr, stdout);
1.5 provos 152: }
153:
1.15 millert 154: int
155: main(int argc, char **argv)
1.1 downsj 156: {
1.15 millert 157: int opt;
158: int operation = -1;
159: int prompt = 0;
160: int rounds;
1.18 millert 161: void *extra = NULL; /* Store salt or number of rounds */
1.27 jdixon 162: const char *errstr;
1.15 millert 163:
164: if (strcmp(__progname, "makekey") == 0)
165: operation = DO_MAKEKEY;
166:
1.18 millert 167: while ((opt = getopt(argc, argv, "kmps:b:c:")) != -1) {
1.15 millert 168: switch (opt) {
169: case 'k': /* Stdin/Stdout Unix crypt */
170: if (operation != -1 || prompt)
171: usage();
172: operation = DO_MAKEKEY;
173: break;
174:
175: case 'm': /* MD5 password hash */
176: if (operation != -1)
177: usage();
178: operation = DO_MD5;
179: break;
180:
181: case 'p':
182: if (operation == DO_MAKEKEY)
183: usage();
184: prompt = 1;
185: break;
186:
187: case 's': /* Unix crypt (DES) */
188: if (operation != -1 || optarg[0] == '$')
189: usage();
190: operation = DO_DES;
191: extra = optarg;
192: break;
193:
194: case 'b': /* Blowfish password hash */
195: if (operation != -1)
196: usage();
197: operation = DO_BLF;
1.29 tedu 198: if (strcmp(optarg, "a") == 0)
199: rounds = ideal_rounds();
200: else
201: rounds = strtonum(optarg, 1, INT_MAX, &errstr);
1.27 jdixon 202: if (errstr != NULL)
203: errx(1, "%s: %s", errstr, optarg);
1.15 millert 204: extra = &rounds;
1.18 millert 205: break;
206:
207: case 'c': /* user login class */
208: extra = optarg;
209: operation = -1;
1.15 millert 210: break;
211:
212: default:
213: usage();
214: }
1.1 downsj 215: }
216:
1.15 millert 217: if (((argc - optind) < 1) || operation == DO_MAKEKEY) {
218: char line[BUFSIZ], *string;
1.1 downsj 219:
1.15 millert 220: if (prompt) {
1.20 otto 221: if ((string = getpass("Enter string: ")) == NULL)
222: err(1, "getpass");
1.15 millert 223: print_passwd(string, operation, extra);
224: (void)fputc('\n', stdout);
225: } else {
1.28 krw 226: size_t len;
1.15 millert 227: /* Encrypt stdin to stdout. */
228: while (!feof(stdin) &&
229: (fgets(line, sizeof(line), stdin) != NULL)) {
1.28 krw 230: len = strlen(line);
231: if (len == 0 || line[0] == '\n')
1.15 millert 232: continue;
1.28 krw 233: if (line[len - 1] == '\n')
234: line[len - 1] = '\0';
235:
236: print_passwd(line, operation, extra);
1.15 millert 237:
238: if (operation == DO_MAKEKEY) {
239: fflush(stdout);
240: break;
241: }
242: (void)fputc('\n', stdout);
243: }
244: }
1.9 alex 245: } else {
1.15 millert 246: char *string;
247:
248: /* can't combine -p with a supplied string */
249: if (prompt)
250: usage();
251:
252: /* Perhaps it isn't worth worrying about, but... */
253: if ((string = strdup(argv[optind])) == NULL)
254: err(1, NULL);
255: /* Wipe the argument. */
256: memset(argv[optind], 0, strlen(argv[optind]));
257:
1.9 alex 258: print_passwd(string, operation, extra);
259:
1.15 millert 260: (void)fputc('\n', stdout);
261:
262: /* Wipe our copy, before we free it. */
263: memset(string, 0, strlen(string));
264: free(string);
1.1 downsj 265: }
1.15 millert 266: exit(0);
1.1 downsj 267: }