*/
#include <ucw/lib.h>
+#include <ucw/base64.h>
#include <ucw/gary.h>
#include <ucw/stkstring.h>
+#include <ucw/string.h>
+#include <ucw/unaligned.h>
#include <errno.h>
#include <fcntl.h>
+#include <gcrypt.h>
#include <time.h>
#include <unistd.h>
#include "subauthd.h"
+struct auth_token *auth_fake_token;
+
#define HASH_NODE struct auth_user
#define HASH_PREFIX(x) user_hash_##x
#define HASH_KEY_ENDSTRING login
return aa;
}
+struct auth_token *auth_find_token_passwd(struct auth_acct *aa)
+{
+ CLIST_FOR_EACH(struct auth_token *, at, aa->tokens)
+ if (at->type == TOKEN_PASSWORD)
+ return at;
+ return NULL;
+}
+
+struct auth_token *auth_find_token_generated(struct auth_acct *aa, char *ident)
+{
+ CLIST_FOR_EACH(struct auth_token *, at, aa->tokens)
+ if (at->type == TOKEN_GENERATED && !strcmp(at->ident, ident))
+ return at;
+ return NULL;
+}
+
void auth_delete_user(struct auth_user *au)
{
struct auth_acct *aa;
return at;
}
+static void auth_hash(char *hash_text, struct auth_token *at, const char *passwd)
+{
+ // This is PBKDF2 based on SHA-256-HMAC
+
+ gcry_md_hd_t md;
+ if (gcry_md_open(&md, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
+ die("gcry_md_open(CGRY_MD_SHA256) failed");
+ if (gcry_md_setkey(md, passwd, strlen(passwd)) != GPG_ERR_NO_ERROR)
+ die("gcry_md_setkey() failed");
+
+ byte current_hash[HASH_BYTES];
+ gcry_md_write(md, at->salt, strlen(at->salt));
+ byte zeroes[4] = { 0, 0, 0, 0 };
+ gcry_md_write(md, zeroes, 4);
+ memcpy(current_hash, gcry_md_read(md, 0), HASH_BYTES);
+
+ byte accumulator[HASH_BYTES];
+ memcpy(accumulator, current_hash, HASH_BYTES);
+
+ for (uint i=1; i < at->iterations; i++)
+ {
+ gcry_md_reset(md);
+ gcry_md_write(md, current_hash, HASH_BYTES);
+ memcpy(current_hash, gcry_md_read(md, 0), HASH_BYTES);
+ for (uint j=0; j<HASH_BYTES; j++)
+ accumulator[j] ^= current_hash[j];
+ }
+
+ gcry_md_close(md);
+
+ uint out_len = base64_encode(hash_text, accumulator, HASH_BYTES);
+ hash_text[out_len] = 0;
+}
+
+static void set_salt(struct auth_token *at)
+{
+ byte salt_bytes[DEFAULT_SALT_BYTES];
+ gcry_randomize(salt_bytes, DEFAULT_SALT_BYTES, GCRY_STRONG_RANDOM);
+
+ char salt_text[2*DEFAULT_SALT_BYTES + 1];
+ uint salt_len = base64_encode(salt_text, salt_bytes, DEFAULT_SALT_BYTES);
+ salt_text[salt_len] = 0;
+
+ at->salt = xstrdup(salt_text);
+ at->iterations = DEFAULT_HASH_ITERATIONS;
+}
+
void auth_set_token_passwd(struct auth_token *at, const char *passwd)
{
at->type = TOKEN_PASSWORD;
- at->salt = xstrdup("???");
- at->hash = xstrdup("???");
+ set_salt(at);
+
+ char hash[MAX_TEXT_HASH_SIZE];
+ auth_hash(hash, at, passwd);
+ at->hash = xstrdup(hash);
+}
+
+char *auth_set_token_generated(struct auth_token *at, const char *comment)
+{
+ char ident_text[2*DEFAULT_IDENT_BYTES + 1];
+ do
+ {
+ byte ident_bytes[DEFAULT_IDENT_BYTES];
+ gcry_randomize(ident_bytes, DEFAULT_IDENT_BYTES, GCRY_STRONG_RANDOM);
+ mem_to_hex(ident_text, ident_bytes, DEFAULT_IDENT_BYTES, 0);
+ }
+ while (auth_find_token_generated(at->acct, ident_text));
+
+ at->type = TOKEN_GENERATED;
+ at->ident = xstrdup(ident_text);
+ at->comment = xstrdup(comment);
+ set_salt(at);
+
+ byte token_bytes[DEFAULT_GENERATED_BYTES];
+ gcry_randomize(token_bytes, DEFAULT_GENERATED_BYTES, GCRY_STRONG_RANDOM);
+
+ uint token_len = 2*DEFAULT_IDENT_BYTES + 1 + 2*DEFAULT_GENERATED_BYTES + 1;
+ char *token_text = xmalloc(token_len);
+ memcpy(token_text, ident_text, 2*DEFAULT_IDENT_BYTES);
+ char *token_rhs = token_text + 2*DEFAULT_IDENT_BYTES;
+ *token_rhs++ = '-';
+ uint out_len = base64_encode(token_rhs, token_bytes, DEFAULT_GENERATED_BYTES);
+ if (out_len > 0 && token_rhs[out_len-1] == '=')
+ out_len--;
+ token_rhs[out_len] = 0;
+
+ char hash[MAX_TEXT_HASH_SIZE];
+ auth_hash(hash, at, token_rhs);
+ at->hash = xstrdup(hash);
+
+ return token_text;
+}
+
+bool auth_check_token(struct auth_token *at, const char *passwd)
+{
+ char hash[MAX_TEXT_HASH_SIZE];
+ auth_hash(hash, at, passwd);
+ return !strcmp(at->hash, hash);
+}
+
+static void auth_create_fake_token(void)
+{
+ struct auth_token *at = xmalloc_zero(sizeof(*at));
+ auth_set_token_passwd(at, "TheKeyIsUnderTheFlyingCarpet");
+ auth_fake_token = at;
}
static void NONRET db_corrupted(const char *reason)
const char *salt = get_string(jt, "s");
const char *hash = get_string(jt, "h");
const char *cmt = get_string(jt, "c");
+ const char *ident = get_string(jt, "i");
if (!salt || !hash)
db_corrupted("Token must have salt and hash");
- uint lastmod;
- if (!get_uint(jt, "m", &lastmod))
- db_corrupted("Token has invalid last modified time");
-
struct auth_token *at = auth_create_token(aa);
at->type = type;
at->salt = xstrdup(salt);
at->hash = xstrdup(hash);
at->comment = xstrdup(cmt);
+ at->ident = xstrdup(ident);
+
+ uint lastmod;
+ if (!get_uint(jt, "m", &lastmod))
+ db_corrupted("Token has invalid last modified time");
at->last_modified = lastmod;
+
+ if (!get_uint(jt, "n", &at->iterations))
+ db_corrupted("Token has invalid number of hash iterations");
}
}
}
json_object_set(jt, "h", json_new_string_ref(js, at->hash));
if (at->comment)
json_object_set(jt, "c", json_new_string_ref(js, at->comment));
+ if (at->ident)
+ json_object_set(jt, "i", json_new_string_ref(js, at->ident));
+ json_object_set(jt, "n", json_new_number(js, at->iterations));
json_object_set(jt, "m", json_new_number(js, at->last_modified));
}
if (GARY_SIZE(jts->elements))
void auth_init(void)
{
+ if (!gcry_check_version(GCRYPT_VERSION))
+ die("libgcrypt version mismatch");
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
user_hash_init();
db_read();
+ auth_create_fake_token();
}