1 /* $OpenBSD: encrypt.c,v 1.30 2013/11/12 13:54:51 deraadt Exp $ */ 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> 29 #include <ctype.h> 30 #include <err.h> 31 #include <errno.h> 32 #include <pwd.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <login_cap.h> 38 #include <limits.h> 39 40 /* 41 * Very simple little program, for encrypting passwords from the command 42 * line. Useful for scripts and such. 43 */ 44 45 #define DO_MAKEKEY 0 46 #define DO_DES 1 47 #define DO_MD5 2 48 #define DO_BLF 3 49 50 extern char *__progname; 51 char buffer[_PASSWORD_LEN]; 52 53 void usage(void); 54 int ideal_rounds(void); 55 void print_passwd(char *, int, void *); 56 57 void 58 usage(void) 59 { 60 61 (void)fprintf(stderr, 62 "usage: %s [-km] [-b rounds] [-c class] [-p | string] [-s salt]\n", 63 __progname); 64 exit(1); 65 } 66 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 72 ideal_rounds(void) 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 101 void 102 print_passwd(char *string, int operation, void *extra) 103 { 104 char msalt[3], *salt, *cryptstr; 105 login_cap_t *lc; 106 int pwd_gensalt(char *, int, login_cap_t *, char); 107 void to64(char *, u_int32_t, int n); 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 } 118 strlcpy(msalt, &string[8], sizeof msalt); 119 salt = msalt; 120 break; 121 122 case DO_MD5: 123 strlcpy(buffer, "$1$", sizeof buffer); 124 to64(&buffer[3], arc4random(), 4); 125 to64(&buffer[7], arc4random(), 4); 126 strlcpy(buffer + 11, "$", sizeof buffer - 11); 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: 140 if ((lc = login_getclass(extra)) == NULL) 141 errx(1, "unable to get login class `%s'", 142 extra ? (char *)extra : "default"); 143 if (!pwd_gensalt(buffer, _PASSWORD_LEN, lc, 'l')) 144 errx(1, "can't generate salt"); 145 salt = buffer; 146 break; 147 } 148 149 if ((cryptstr = crypt(string, salt)) == NULL) 150 errx(1, "crypt failed"); 151 fputs(cryptstr, stdout); 152 } 153 154 int 155 main(int argc, char **argv) 156 { 157 int opt; 158 int operation = -1; 159 int prompt = 0; 160 int rounds; 161 void *extra = NULL; /* Store salt or number of rounds */ 162 const char *errstr; 163 164 if (strcmp(__progname, "makekey") == 0) 165 operation = DO_MAKEKEY; 166 167 while ((opt = getopt(argc, argv, "kmps:b:c:")) != -1) { 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; 198 if (strcmp(optarg, "a") == 0) 199 rounds = ideal_rounds(); 200 else 201 rounds = strtonum(optarg, 1, INT_MAX, &errstr); 202 if (errstr != NULL) 203 errx(1, "%s: %s", errstr, optarg); 204 extra = &rounds; 205 break; 206 207 case 'c': /* user login class */ 208 extra = optarg; 209 operation = -1; 210 break; 211 212 default: 213 usage(); 214 } 215 } 216 217 if (((argc - optind) < 1) || operation == DO_MAKEKEY) { 218 char line[BUFSIZ], *string; 219 220 if (prompt) { 221 if ((string = getpass("Enter string: ")) == NULL) 222 err(1, "getpass"); 223 print_passwd(string, operation, extra); 224 (void)fputc('\n', stdout); 225 } else { 226 size_t len; 227 /* Encrypt stdin to stdout. */ 228 while (!feof(stdin) && 229 (fgets(line, sizeof(line), stdin) != NULL)) { 230 len = strlen(line); 231 if (len == 0 || line[0] == '\n') 232 continue; 233 if (line[len - 1] == '\n') 234 line[len - 1] = '\0'; 235 236 print_passwd(line, operation, extra); 237 238 if (operation == DO_MAKEKEY) { 239 fflush(stdout); 240 break; 241 } 242 (void)fputc('\n', stdout); 243 } 244 } 245 } else { 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 258 print_passwd(string, operation, extra); 259 260 (void)fputc('\n', stdout); 261 262 /* Wipe our copy, before we free it. */ 263 memset(string, 0, strlen(string)); 264 free(string); 265 } 266 exit(0); 267 } 268