Skip to content

Instantly share code, notes, and snippets.

@stbuehler
Created August 25, 2013 00:36
Show Gist options
  • Save stbuehler/6331188 to your computer and use it in GitHub Desktop.
Save stbuehler/6331188 to your computer and use it in GitHub Desktop.
create {CRAM-MD5} password hashes for dovecot
/*
gcc -o cram-md5 `pkg-config --cflags --libs openssl` cram-md5.c && ./cram-md5
*/
#include <string.h>
#include <openssl/md5.h>
#include <openssl/crypto.h>
static void store_int(unsigned char *d, MD5_LONG l) {
d[0] = l & 0xff;
d[1] = (l >> 8) & 0xff;
d[2] = (l >> 16) & 0xff;
d[3] = (l >> 24) & 0xff;
}
static void md5_ctx_to_digest(unsigned char *md, MD5_CTX *ctx) {
store_int(md+0 , ctx->A);
store_int(md+4 , ctx->B);
store_int(md+8 , ctx->C);
store_int(md+12, ctx->D);
}
static void hexdigest(char *hex, const unsigned char *md) {
static const char hexchars[17] = "0123456789abcdef";
int i;
for (i = 0; i < MD5_DIGEST_LENGTH; ++i) {
hex[2*i ] = hexchars[md[i] >> 4];
hex[2*i+1] = hexchars[md[i] & 0xf];
}
hex[2*MD5_DIGEST_LENGTH] = '\0';
}
static void cram_md5(const char *key) {
MD5_CTX ctx;
int keylen = strlen(key);
unsigned char bkey[MD5_CBLOCK] = { 0 };
unsigned char padkey[MD5_CBLOCK];
unsigned char digest[MD5_DIGEST_LENGTH];
unsigned char out[10 + 4 * MD5_DIGEST_LENGTH + 1];
int i;
if (keylen < MD5_CBLOCK) {
memcpy(bkey, key, keylen);
} else {
MD5_Init(&ctx);
MD5_Update(&ctx, key, keylen);
MD5_Final(bkey, &ctx);
}
memcpy(out, "{CRAM-MD5}", 11);
/* opad */
for (i = 0; i < MD5_CBLOCK; ++i) padkey[i] = bkey[i] ^ 0x5c;
MD5_Init(&ctx);
MD5_Transform(&ctx, padkey);
md5_ctx_to_digest(digest, &ctx);
hexdigest(out + 10, digest);
/* ipad */
for (i = 0; i < MD5_CBLOCK; ++i) padkey[i] = bkey[i] ^ 0x36;
MD5_Init(&ctx);
MD5_Transform(&ctx, padkey);
md5_ctx_to_digest(digest, &ctx);
hexdigest(out + 42, digest);
out[74] = '\0';
puts(out);
OPENSSL_cleanse(&ctx,sizeof(ctx));
OPENSSL_cleanse(&bkey,sizeof(bkey));
OPENSSL_cleanse(&padkey,sizeof(padkey));
OPENSSL_cleanse(&digest,sizeof(digest));
OPENSSL_cleanse(&out,sizeof(out));
}
#include <termios.h>
#include <stdio.h>
static void echo_off() {
struct termios t;
tcgetattr(0, &t);
t.c_lflag &= ~ECHO;
tcsetattr(0, TCSAFLUSH, &t);
}
static void echo_on() {
struct termios t;
tcgetattr(0, &t);
t.c_lflag |= ECHO;
tcsetattr(0, TCSAFLUSH, &t);
}
int main() {
char *password = NULL;
size_t pwalloc = 0, pwlen;
ssize_t r;
fputs("Password: ", stdout);
echo_off();
r = getline(&password, &pwalloc, stdin);
echo_on();
puts("");
if (-1 == r) return -1;
pwlen = strlen(password);
while (pwlen > 0 && iscntrl(password[pwlen-1])) --pwlen;
password[pwlen] = '\0';
cram_md5(password);
OPENSSL_cleanse(password,pwalloc);
free(password);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment