e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen/*
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi * OTP hash generation.
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen * Copyright (c) 2006 Andrey Panin <pazke@donpac.ru>
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen * This software is released under the MIT license.
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen */
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "lib.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "md4.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "md5.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "sha1.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "otp.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstruct digest {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const char *name;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen void (*init)(void *ctx);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen void (*update)(void *ctx, const void *data, const size_t size);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen void (*final)(void *ctx, void *res);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen void (*otp_final)(void *ctx, void *res);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen};
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstruct digest_context {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const struct digest *digest;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen union {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen struct md4_context md4_ctx;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen struct md5_context md5_ctx;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen struct sha1_ctxt sha1_ctx;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen } ctx;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen};
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstatic void md4_fold(struct md4_context *ctx, void *res)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen uint32_t tmp[4], *p = res;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen md4_final(ctx, (unsigned char *) tmp);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *p++ = tmp[0] ^ tmp[2];
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *p = tmp[1] ^ tmp[3];
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstatic void md5_fold(struct md5_context *ctx, void *res)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen uint32_t tmp[4], *p = res;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen md5_final(ctx, (unsigned char *) tmp);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *p++ = tmp[0] ^ tmp[2];
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *p = tmp[1] ^ tmp[3];
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen/*
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen * Sometimes I simply can't look at code generated by gcc.
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen */
4081894c16e50f37639d9826ebca4394b398c35eTimo Sirainenstatic inline uint32_t swab_uint32(uint32_t val)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#if defined(__GNUC__) && defined(__i386__)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen asm("xchgb %b0, %h0\n"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen "rorl $16, %0\n"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen "xchgb %b0, %h0\n"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen :"=q" (val)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen : "0" (val));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#else
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ((val & 0xff0000) >> 8) | ((val >> 24) & 0xff);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#endif
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return val;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstatic void sha1_fold(struct sha1_ctxt *ctx, void *res)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen uint32_t tmp[5], *p = res;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen sha1_result(ctx, tmp);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
4081894c16e50f37639d9826ebca4394b398c35eTimo Sirainen *p++ = swab_uint32(tmp[0] ^ tmp[2] ^ tmp[4]);
4081894c16e50f37639d9826ebca4394b398c35eTimo Sirainen *p = swab_uint32(tmp[1] ^ tmp[3]);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#define F_INIT(name) ((void (*)(void *)) (name))
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#define F_UPDATE(name) ((void (*)(void *, const void *, size_t)) (name))
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#define F_FINAL(name) ((void (*)(void *, void *)) (name))
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#define F_FOLD(name) ((void (*)(void *, void *)) (name))
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstatic const struct digest digests[] = {
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody { "md4", F_INIT(md4_init), F_UPDATE(md4_update), F_FINAL(md4_final), F_FOLD(md4_fold) },
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody { "md5", F_INIT(md5_init), F_UPDATE(md5_update), F_FINAL(md5_final), F_FOLD(md5_fold) },
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody { "sha1", F_INIT(sha1_init), F_UPDATE(sha1_loop), F_FINAL(sha1_result), F_FOLD(sha1_fold) },
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen};
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#undef F_INIT
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#undef F_UPDATE
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#undef F_FINAL
8e018b1e83a6e22d8c520186e3e74a4d9fcb8888Phil Carmody#undef F_FOLD
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenconst char *digest_name(unsigned int algo)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen i_assert(algo < N_ELEMENTS(digests));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return digests[algo].name;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint digest_find(const char *name)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen unsigned int i;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen for (i = 0; i < N_ELEMENTS(digests); i++)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (strcmp(name, digests[i].name) == 0)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return i;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenvoid digest_init(struct digest_context *ctx, const unsigned int algo)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen i_assert(algo < N_ELEMENTS(digests));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ctx->digest = digests + algo;
e2163b3ae3a800a1b4ea755450171733e2fc7bc9Timo Sirainen ctx->digest->init(&ctx->ctx);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenvoid digest_update(struct digest_context *ctx, const void *data,
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const size_t size)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e2163b3ae3a800a1b4ea755450171733e2fc7bc9Timo Sirainen ctx->digest->update(&ctx->ctx, data, size);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenvoid digest_final(struct digest_context *ctx, unsigned char *result)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e2163b3ae3a800a1b4ea755450171733e2fc7bc9Timo Sirainen ctx->digest->final(&ctx->ctx, result);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenvoid digest_otp_final(struct digest_context *ctx, unsigned char *result)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e2163b3ae3a800a1b4ea755450171733e2fc7bc9Timo Sirainen ctx->digest->otp_final(&ctx->ctx, result);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenvoid otp_hash(unsigned int algo, const char *seed, const char *passphrase,
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned int step, unsigned char *result)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen struct digest_context ctx;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_init(&ctx, algo);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_update(&ctx, seed, strlen(seed));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_update(&ctx, passphrase, strlen(passphrase));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_otp_final(&ctx, result);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen while (step-- > 0) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_init(&ctx, algo);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_update(&ctx, result, OTP_HASH_SIZE);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_otp_final(&ctx, result);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenvoid otp_next_hash(unsigned int algo, const unsigned char *prev,
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned char *result)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen struct digest_context ctx;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_init(&ctx, algo);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_update(&ctx, prev, OTP_HASH_SIZE);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen digest_otp_final(&ctx, result);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}