Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
Added bcrypt_erlang port program
  • Loading branch information
hntrmrrs committed Nov 3, 2008
1 parent 43da274 commit 19cad789f83f5b7c792e5af93b013a7f2b885e57
Showing 1 changed file with 217 additions and 0 deletions.
@@ -0,0 +1,217 @@
/*
* Copyright (c) 2008 Hunter Morris <huntermorris@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

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

#define BCRYPT_VERSION '2'

#define dec_int16(s) ((((unsigned char*) (s))[0] << 8) | \
(((unsigned char*) (s))[1]))

#define enc_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \
((unsigned char*)(s))[1] = (i) & 0xff;}

#define BUFSIZE (1 << 16)
#define CMD_SALT 0
#define CMD_HASHPW 1

char *bcrypt(const char *, const char *);
void encode_salt(char *, u_int8_t *, u_int16_t, u_int8_t);

/* These methods came from the Erlang port command tutorial:
* http://www.erlang.org/doc/tutorial/c_port.html#4.2
*/
static int
read_buf(int fd, unsigned char *buf, int len)
{
int i, got = 0;
do {
if ((i = read(fd, buf+got, len-got)) <= 0) {
if (i == 0) return got;
if (errno != EINTR)
return got;
i = 0;
}
got += i;
} while (got < len);
return (len);
}

static int
read_cmd(unsigned char *buf)
{
int len;
if (read_buf(0, buf, 2) != 2)
return 0;
len = dec_int16(buf);
if (read_buf(0, buf, len) != len)
return 0;
return 1;
}

static int
write_buf(int fd, unsigned char *buf, int len)
{
int i, done = 0;
do {
if ((i = write(fd, buf+done, len-done)) < 0) {
if (errno != EINTR)
return (i);
i = 0;
}
done += i;
} while (done < len);
return (len);
}

static int
write_cmd(unsigned char *buf, int len)
{
unsigned char hd[2];
enc_int16(len, hd);
if (write_buf(1, hd, 2) != 2)
return 0;
if (write_buf(1, buf, len) != len)
return 0;
return 1;
}

static int process_reply(ETERM *pid, int cmd, const char *res)
{
ETERM *result;
int len, retval;
unsigned char *buf;
result = erl_format("{~i, ~w, ~s}", cmd, pid, res);
len = erl_term_len(result);
buf = erl_malloc(len);
erl_encode(result, buf);
retval = write_cmd(buf, len);
erl_free_term(result);
erl_free(buf);
return retval;
}

static int process_encode_salt(ETERM *pid, ETERM *data)
{
int retval = 0;
ETERM *pattern, *cslt, *lr;
char *csalt = NULL;
long log_rounds = -1;
int csaltlen = -1;
char ret[64];
pattern = erl_format("{Csalt, LogRounds}");
if (erl_match(pattern, data)) {
cslt = erl_var_content(pattern, "Csalt");
csalt = erl_iolist_to_string(cslt);
csaltlen = strlen(csalt);
lr = erl_var_content(pattern, "LogRounds");
log_rounds = ERL_INT_UVALUE(lr);
if (16 != csaltlen) {
retval = process_reply(pid, CMD_SALT, "Invalid salt length");
} else if (log_rounds < 4 || log_rounds > 31) {
retval = process_reply(pid, CMD_SALT, "Invalid number of rounds");
} else {
encode_salt(ret, csalt, csaltlen, log_rounds);
retval = process_reply(pid, CMD_SALT, ret);
}
erl_free_term(cslt);
erl_free_term(lr);
erl_free(csalt);
};
erl_free_term(pattern);
return retval;
}

static int process_hashpw(ETERM *pid, ETERM *data)
{
int retval = 0;
ETERM *pattern, *pwd, *slt;
char *password, *salt;
char *ret;
pattern = erl_format("{Pass, Salt}");
if (erl_match(pattern, data)) {
pwd = erl_var_content(pattern, "Pass");
password = erl_iolist_to_string(pwd);
slt = erl_var_content(pattern, "Salt");
salt = erl_iolist_to_string(slt);
if (NULL == (ret = bcrypt(password, salt)) ||
0 == strcmp(ret, ":")) {
retval = process_reply(pid, CMD_HASHPW, "Invalid salt");
} else {
retval = process_reply(pid, CMD_HASHPW, ret);
}
erl_free_term(pwd);
erl_free_term(slt);
erl_free(password);
erl_free(salt);
};
erl_free_term(pattern);
return retval;
}

static int
process_command(unsigned char *buf)
{
int retval = 0;
ETERM *pattern, *tuple, *cmd, *port, *data;
pattern = erl_format("{Cmd, Port, Data}");
tuple = erl_decode(buf);
if (erl_match(pattern, tuple)) {
cmd = erl_var_content(pattern, "Cmd");
port = erl_var_content(pattern, "Port");
data = erl_var_content(pattern, "Data");
switch (ERL_INT_VALUE(cmd)) {
case CMD_SALT:
retval = process_encode_salt(port, data);
break;
case CMD_HASHPW:
retval = process_hashpw(port, data);
break;
};
erl_free_term(cmd);
erl_free_term(port);
erl_free_term(data);
}
erl_free_term(pattern);
erl_free_term(tuple);
return retval;
}

static void
loop(void)
{
unsigned char buf[BUFSIZE];
int retval = 0;
do {
if (read_cmd(buf) > 0)
retval = process_command(buf);
else
retval = 0;
} while (retval);
}

int
main(int argc, char *argv[])
{
erl_init(NULL, 0);
loop();
return 0;
}

0 comments on commit 19cad78

Please sign in to comment.