aboutsummaryrefslogtreecommitdiffstats
path: root/ext/tweetpwhash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/tweetpwhash.c')
-rw-r--r--ext/tweetpwhash.c130
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;
+}