diff options
Diffstat (limited to 'crypt.c')
-rw-r--r-- | crypt.c | 163 |
1 files changed, 163 insertions, 0 deletions
@@ -0,0 +1,163 @@ +/* + * Copyright 2019 Offensive Security + * Copyright 2019 Raphaƫl Hertzog <raphael@offensive-security.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/random.h> +#include <crypt.h> + +void +usage(const char* name, int exitcode) +{ + fprintf(stderr, "Usage: %s <command>\n", name); + fprintf(stderr, "Valid commands:\n"); + fprintf(stderr, " --help: display this output\n"); + fprintf(stderr, " --generate <salt>: read password from stdin and print hashed version\n"); + fprintf(stderr, " --check <hash>: read password from stdin and check it against supplied hash\n"); + fprintf(stderr, " Exits with error 0 when password matched, 1 otherwise.\n"); + exit(exitcode); +} + +void +read_password(char *buffer, int bufsize) +{ + int size = -1, total = 0, i = 0; + + while ((size != 0) && (total < bufsize - 1)) { + size = read(0, buffer+total, bufsize - total); + if (size != -1) { + total += size; + } + } + buffer[total+1] = '\0'; + for(i = 0; i < total; i++) { + if ((buffer[i] == '\n') || (buffer[i] == '\r')) { + buffer[i] = '\0'; + break; + } + } + if (strlen(buffer) == 0) { + fprintf(stderr, "ERROR: no password supplied"); + exit(1); + } +} + +char* +gen_salt() +{ + static const char alphanum[] = "123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static char salt[16]; + int i, index; + unsigned int seed; + ssize_t ret; + + ret = getrandom(&seed, sizeof(seed), 0); + if (ret != sizeof(seed)) { + fprintf(stderr, "ERROR: failed to get random data\n"); + exit(2); + } + srandom(seed); + + salt[0] = '$'; + salt[1] = '6'; + salt[2] = '$'; + for (i = 3; i < 11; i++) { + index = random() % (sizeof(alphanum) - 1); + salt[i] = alphanum[index]; + } + salt[11] = '$'; + salt[12] = '\0'; + return salt; +} + +char* +extract_salt(char* hash) +{ + static char salt[24]; + + if (hash[0] != '$') { + /* Traditional crypt hash with 2 characters */ + salt[0] = hash[0]; + salt[1] = hash[1]; + salt[2] = '\0'; + } else { + /* Hash delimited by $ characters */ + char *p, *end; + int i; + + p = hash; + end = strrchr(hash, '$'); + for(i = 0; p <= end && i < sizeof(salt) - 1; i++) { + salt[i] = *p; + p++; + } + salt[i] = '\0'; + } + return salt; +} + +int +main (int argc, char* argv[]) +{ + static char buffer[256]; + char *crypted, *salt; + + if (argc == 1) { + usage(argv[0], 1); + } + + if (strcmp(argv[1], "--help") == 0) { + usage(argv[0], 0); + } else if (strcmp(argv[1], "--generate") == 0) { + read_password(buffer, sizeof(buffer)); + salt = (argc > 2 && strlen(argv[2])) ? argv[2] : gen_salt(); + crypted = crypt(buffer, salt); + if (crypted == NULL || ( + strlen(crypted) < 13 && + strncmp(crypted, "*", 1) == 0 && + strcmp(crypted, salt) != 0 + )) { + fprintf(stderr, "ERROR: crypt() failed to return anything with salt '%s'", salt); + exit(1); + } + printf("%s\n", crypted); + } else if (strcmp(argv[1], "--check") == 0) { + read_password(buffer, sizeof(buffer)); + if (argc < 3) { + fprintf(stderr, "ERROR: missing <hash> argument after --check"); + exit(1); + } + salt = extract_salt(argv[2]); + crypted = crypt(buffer, salt); + if (crypted == NULL) + exit(1); + if (strcmp(crypted, argv[2]) == 0) + exit(0); + else + exit(1); + } else { + usage(argv[0], 1); + } + + return 0; +} + |