summaryrefslogtreecommitdiffstats
path: root/crypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypt.c')
-rw-r--r--crypt.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/crypt.c b/crypt.c
new file mode 100644
index 0000000..65b55d0
--- /dev/null
+++ b/crypt.c
@@ -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;
+}
+