diff options
Diffstat (limited to 'ext/tweetpwhash.c')
| -rw-r--r-- | ext/tweetpwhash.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/ext/tweetpwhash.c b/ext/tweetpwhash.c new file mode 100644 index 0000000..cd738cf --- /dev/null +++ b/ext/tweetpwhash.c @@ -0,0 +1,130 @@ +#include "tweetnacl.h" +#include "tweetpwhash.h" +#define FOR(i, n) for (i = 0; i < n; ++i) +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define sv static void + +#define HB crypto_hash_BYTES +#define BB crypto_hashblocks_BLOCKBYTES +#define SB crypto_pwhash_SALTBYTES + +typedef unsigned char u8; +typedef unsigned long long u64; + +sv ts64(u8 *x, u64 u) +{ + int i; + for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; } +} + +static const u8 iv[64] = { + 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, + 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, + 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, + 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, + 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, + 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, + 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, + 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +}; + +typedef struct { + u8 h[HB]; + u8 m[BB]; + u64 n; + u64 l; +} ctx; + +sv chi(ctx *c) +{ + u64 i; + + FOR(i, HB) c->h[i] = iv[i]; + c->n = c->l = 0; +} + +sv chu(ctx *c, const u8 *m, u64 n) +{ + u64 i, t; + + c->l += n; + + while (n) { + t = MIN(n, BB - c->n); + FOR(i, t) c->m[c->n + i] = m[i]; + c->n += t; + + crypto_hashblocks(c->h, c->m, c->n); + c->n &= (BB - 1); + m += t; + n -= t; + } +} + +sv chf(u8 *out, ctx *c) +{ + u8 x[256]; + u64 i, n = c->n; + + FOR(i, 256) x[i] = 0; + FOR(i, n) x[i] = c->m[i]; + x[n] = 128; + + n = 256 - 128 * (n < 112); + x[n - 9] = c->l >> 61; + ts64(x + n - 8, c->l << 3); + crypto_hashblocks(c->h, x, n); + + FOR(i, HB) out[i] = c->h[i]; +} + +sv prf(u8 *out, const u8 *m, u64 mln, const u8 *k, u64 kln) +{ + ctx c; + u64 j; + u8 hk[HB], ik[BB], ok[BB], ih[HB]; + + if (kln > BB) { + chi(&c); chu(&c, k, kln); chf(hk, &c); + k = hk; + kln = HB; + } + + FOR(j, BB) ik[j] = ok[j] = 0; + FOR(j, kln) ik[j] = ok[j] = k[j]; + FOR(j, BB) ik[j] ^= 0x36; + FOR(j, BB) ok[j] ^= 0x5c; + + chi(&c); chu(&c, ik, BB); chu(&c, m, mln); chf(ih, &c); + chi(&c); chu(&c, ok, BB); chu(&c, ih, HB); chf(out, &c); +} + +int crypto_pwhash(u8 *out, u64 outln, const u8 *p, u64 pln, const u8 *s, u64 c) +{ + u64 i, j, b, nb, bl, o; + u8 u[HB], t[HB], bs[SB + 4]; + + FOR(i, SB) bs[i] = s[i]; + nb = (outln + HB - 1) / HB; + + for (b = 1, o = 0; b <= nb; b++) { + bs[SB + 0] = (b >> 24) & 0xff; + bs[SB + 1] = (b >> 16) & 0xff; + bs[SB + 2] = (b >> 8) & 0xff; + bs[SB + 3] = b & 0xff; + + prf(u, bs, SB + 4, p, pln); + FOR(i, HB) t[i] = u[i]; + + FOR(i, c - 1) { + prf(u, u, HB, p, pln); + FOR(j, HB) t[j] ^= u[j]; + } + + bl = MIN(HB, outln - o); + FOR(i, bl) out[o + i] = t[i]; + o += bl; + } + + return 0; +} |