Ted Zlatanov tzz@lifelogs.com writes:
I'm trying to use the Nettle PBKDF2 functionality from Emacs.
Cool! What will it be used for?
I tried this, given alg is a pointer to a nettle_hash:
HMAC_SET_KEY(ctx, alg, SCHARS (key), SDATA (key)); PBKDF2 (ctx, alg->update, alg->digest, alg->digest_size, XINT (iterations), SCHARS (salt), SDATA (salt), outlength, digest);
I'm afraid the HMAC_CTX macro, if that's what you are using, doesn't work so well with the nettle_hash abstraction. It wants to know the concrete type, e.g., struct sha1_ctx, which you don't have if you work with the struct nettle_hash interface.
In the above example, the ctx argument to HMAC_SET_KEY needs to have fields outer, inner and state, each with size (and struct offsets) matching alg->context_size. And the update and digest pointers passed to PBKDF2 must be update and digest for the HMAC operation, *not* for the underlying hash.
To use hmac with an arbitrary nettle_hash object, I'd suggest something like
struct hmac_gen_ctx { const struct nettle_hash *alg; uint8_t state[1]; /* Variable size; three hashing contexts */ };
struct hmac_gen_ctx * hmac_gen_new (const struct nettle_hash *alg, unsigned length, const uint8_t *key) { /* NOTE: This could possibly produce bad alignment; if so, allocate * separate storage for outer, inner and state, or round up the * context size. */ struct hmac_gen_ctx *ctx = xalloc (sizeof(*ctx) - 1 + 3*alg->context_size); ctx->alg = alg; hmac_set_key (ctx->state, /* outer */ ctx->state + ctx->alg->context_size, /* inner */ ctx->state + 2*ctx->alg->context_size, /* hmac state */ ctx->alg, length, key);
return ctx; }
void hmac_gen_update (struct hmac_gen_ctx *ctx, unsigned length, const uint8_t *data) { hmac_update(ctx->state + 2*ctx->alg->context_size, ctx->alg, length, data); }
void hmac_gen_digest (struct hmac_gen_ctx *ctx, unsigned length, uint8_t *digest) { hmac_digest (ctx->state, /* outer */ ctx->state + ctx->alg->context_size, /* inner */ ctx->state + 2*ctx->alg->context_size, /* hmac state */ ctx->alg, length, digest); }
Then you can can pass a struct hmac_gen_ctx * pointer together with the hmac_gen_update and hmac_gen_digest functions to the pbkdf2 call, like
pbkdf2_gen (const struct nettle_hash *alg, unsigned key_length, const uint8_t *key, unsigned iterations, unsigned salt_length, const uint8_t *salt, unsigned length, uint8_t *dst) { struct hmac_gen_ctx *prf = hmac_gen_new (alg, key_length, key); pbkdf2 (prf, (nettle_hash_update_func *) hmac_gen_update, (nettle_hash_digest_func *) hmac_gen_digest, alg->digest_size, iterations, salt_length, salt, length, *dst); free (prf); }
Code above totally untested, but I hope you get the idea.
Any concrete suggestions on how to improve the documentation?
Happy hacking, /Niels