Subversion Repositories MLServ

Rev

Rev 7 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/* $Id: crypt.c 8 2024-09-25 00:57:33Z nishi $ */

#include "cm_crypt.h"

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __linux__
#include <crypt.h>
#endif

const char* cm_crypt_methods[] = {"DES",    "MD5", "Blowfish", "", "", "SHA-256", "SHA-512",
#ifdef __NetBSD__
                                  "Argon2",
#endif
                                  NULL};

char* cm_crypt_spec(int num, const char* string, const char* salt) {
        char* r = NULL;
        if(num == C_DES) {
                r = crypt(string, salt);
        } else if(num == C_MD5 || num == C_SHA256 || num == C_SHA512) {
                char* buffer = malloc(3 + strlen(salt) + 1 + 1);
                buffer[3 + strlen(salt) + 1] = 0;
                sprintf(buffer, "$%d$%s$", num, salt);

                r = crypt(string, buffer);

                free(buffer);
        } else if(num == C_BLOWFISH) {
                char* buffer = malloc(4 + 3 + strlen(salt) + 1 + 1);
                buffer[4 + 3 + strlen(salt) + 1] = 0;
                sprintf(buffer, "$%da$08$%s$", num, salt);

                r = crypt(string, buffer);

                free(buffer);
        }
#ifdef __NetBSD__
        else if(num == C_ARGON2) {
                if(strlen(salt) != 16) return NULL;
                char* buffer = malloc(1 + 8 + 1 + 4 + 1 + 16 + 1 + 1 + 7);
                buffer[1 + 8 + 1 + 4 + 1 + 16 + 1 + 7] = 0;
                sprintf(buffer, "$argon2id$v=19$m=4096$%s$", salt);

                r = crypt(string, buffer);

                free(buffer);
        }
#endif
        if(r == NULL || strcmp(r, "*0") == 0 || strcmp(r, ":") == 0) r = NULL;
        return r;
}

int cm_crypt_try(int num) {
        printf("Trying %s... ", cm_crypt_methods[num]);
        fflush(stdout);

        if(cm_crypt_spec(num, "random", "randomrandomrandomrandom") != NULL) {
                printf("works\n");
                return 1;
        }

#ifdef __NetBSD__
        if(cm_crypt_spec(num, "random", "abcdabcdabcdabcd") != NULL) {
                printf("works\n");
                return 1;
        }
#endif

        printf("does not work\n");

        return 0;
}

int cm_chosen_crypt;

int cm_crypt_init(void) {
        int i;
        int last = -1;
        for(i = C_START + 1; i < C_END; i++) {
                if(strlen(cm_crypt_methods[i]) != 0) {
                        if(cm_crypt_try(i)) {
                                last = i;
                        }
                }
        }
        cm_chosen_crypt = last;
        return last;
}

char* cm_crypt(const char* string) {
        char salt[65];
        salt[64] = 0;
        int i;
        FILE* f = fopen("/dev/urandom", "rb");
        unsigned char c;
        const char usable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
        for(i = 0; i < 64; i++) {
                fread(&c, 1, 1, f);
                salt[i] = c % strlen(usable);
        }
        fclose(f);
        return cm_crypt_spec(cm_chosen_crypt, string, salt);
}