Skip to content

Instantly share code, notes, and snippets.

@stbuehler
Created September 25, 2013 11:07
Show Gist options
  • Save stbuehler/6698128 to your computer and use it in GitHub Desktop.
Save stbuehler/6698128 to your computer and use it in GitHub Desktop.
create crypt() hashes
/*
* Build:
* LDFLAGS=-lcrypt make mkcrypt
*
* Usage:
* mkcrypt [algo [saltlen [randomsource]]]
*
* - reads password from stdin (tries to set echo off)
*
* Defaults to $6$ as algo, 16 for saltlen and /dev/random for the
* random source.
*
* For password verification use: mkcrypt '$6$andsomesalt$' 0
* - that is, specify algo+salt as algo, and 0 as saltlen.
*
* If saltlen is 0 the randomsource isn't used.
*
* Uses the standard crypt() function, no special algos supported.
*/
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termio.h>
#include <unistd.h>
static const char *randomdev = "/dev/random";
static const unsigned char saltchars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int create_salt(unsigned char *buf, int len) {
if (0 == len) return 1;
int c, i;
FILE *rnd = fopen(randomdev, "rb");
if (NULL == rnd) return 0;
for (i = 0; i < len && EOF != (c = fgetc(rnd)); ++i, ++buf) {
unsigned char b = (unsigned char) c;
*buf = saltchars[b % 64];
}
fclose(rnd);
return 1;
}
char *create_password_hash(const char *algo, unsigned int saltlen, const char *password) {
unsigned int algolen = strlen(algo);
/* algo may contains parameters like rounds=... */
if (algolen > 30 || saltlen > 16) return NULL;
unsigned int buflen = algolen + saltlen + 1;
unsigned char buf[buflen];
memset(buf, 0, buflen);
memcpy(buf, algo, algolen);
if (!create_salt(buf + algolen, saltlen)) return NULL;
/* fprintf(stderr, "crypt: '%s'\n", buf); */
char *hash = crypt(password, buf);
if (0 != strncmp(hash, buf, algolen + saltlen)) return NULL;
return hash;
}
void echo_off(struct termio *save) {
struct termio t;
if (ioctl(0, TCGETA, &t) == -1) return;
if (NULL != save) *save = t;
t.c_lflag &= ~(ICANON|ECHO);
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 0;
ioctl(0, TCSETA, &t);
}
void restore(struct termio *save) {
ioctl(0, TCSETA, save);
}
int main(int argc, char **argv) {
char password[1024];
struct termio tsave;
int saltlen = 16;
const char *algo = "$6$";
char *hash;
int pwlen;
if (argc > 1) {
if (0 == strcmp("-h", argv[1]) || 0 == strcmp("-?", argv[1]) || 0 == strcmp("--help", argv[1])) {
fputs("Syntax: mkcrypt [algo [saltlen [randomsource]]]\n", stderr);
exit(2);
}
char *algosalt = strdup(argv[1]);
algo = algosalt;
/* cut off the part after the salt */
if (algosalt[0] == '$' && algosalt[1] != 0 && algosalt[2] == '$') {
algosalt = strchr(algosalt+3, '$');
if (NULL != algosalt) {
*algosalt = 0;
saltlen = 0;
}
} else if (algosalt[0] != 0 && algosalt[1] != 0) {
algosalt[2] = 0;
saltlen = 0;
}
if (argc > 2) {
saltlen = atoi(argv[2]);
}
if (argc > 3) {
randomdev = argv[3];
}
}
/* fprintf(stderr, "Algo: '%s', saltlen: %i\n", algo, saltlen); */
echo_off(&tsave);
fputs("Enter password: ", stdout);
if (NULL == fgets(password, 1024, stdin)) {
restore(&tsave);
fputc('\n', stdout);
exit(1);
}
restore(&tsave);
fputc('\n', stdout);
pwlen = strlen(password);
while (pwlen > 0 && password[pwlen-1] < 32) {
--pwlen;
password[pwlen] = 0;
}
hash = create_password_hash(algo, saltlen, password);
memset(password, 0, sizeof(password));
if (NULL == hash) {
fputs("Failed to generate hash\n", stderr);
exit(1);
}
fputs(hash, stdout);
fputc('\n', stdout);
memset(hash, 0, strlen(hash));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment