mirror of
https://github.com/billbuchanan/appliedcrypto.git
synced 2026-02-21 19:27:58 +00:00
205 lines
5.4 KiB
JavaScript
205 lines
5.4 KiB
JavaScript
var Poly1305KeySize = 32;
|
|
var Poly1305TagSize = 16;
|
|
module.exports = Poly1305;
|
|
function Poly1305(key) {
|
|
if (!(this instanceof Poly1305)) {
|
|
return new Poly1305(key);
|
|
}
|
|
this.buffer = new Buffer(16);
|
|
this.leftover = 0;
|
|
this.r = new Uint16Array(10);
|
|
this.h = new Uint16Array(10);
|
|
this.pad = new Uint16Array(8);
|
|
this.finished = 0;
|
|
|
|
var t = new Uint16Array(8), i;
|
|
|
|
for (i = 8; i--;) t[i] = key.readUInt16LE(i*2);
|
|
|
|
this.r[0] = t[0] & 0x1fff;
|
|
this.r[1] = ((t[0] >>> 13) | (t[1] << 3)) & 0x1fff;
|
|
this.r[2] = ((t[1] >>> 10) | (t[2] << 6)) & 0x1f03;
|
|
this.r[3] = ((t[2] >>> 7) | (t[3] << 9)) & 0x1fff;
|
|
this.r[4] = ((t[3] >>> 4) | (t[4] << 12)) & 0x00ff;
|
|
this.r[5] = (t[4] >>> 1) & 0x1ffe;
|
|
this.r[6] = ((t[4] >>> 14) | (t[5] << 2)) & 0x1fff;
|
|
this.r[7] = ((t[5] >>> 11) | (t[6] << 5)) & 0x1f81;
|
|
this.r[8] = ((t[6] >>> 8) | (t[7] << 8)) & 0x1fff;
|
|
this.r[9] = (t[7] >>> 5) & 0x007f;
|
|
|
|
for (i = 8; i--;) {
|
|
this.h[i] = 0;
|
|
this.pad[i] = key.readUInt16LE( 16+(2*i));
|
|
}
|
|
this.h[8] = 0;
|
|
this.h[9] = 0;
|
|
this.leftover = 0;
|
|
this.finished = 0;
|
|
}
|
|
|
|
|
|
function U16TO8_LE(p, pos, v) {
|
|
p[pos] = v;
|
|
p[pos+1] = v >>> 8;
|
|
}
|
|
|
|
Poly1305.prototype.blocks = function(m, mpos, bytes) {
|
|
var hibit = this.finished ? 0 : (1 << 11);
|
|
var t = new Uint16Array(8),
|
|
d = new Uint32Array(10),
|
|
c = 0, i = 0, j = 0;
|
|
|
|
while (bytes >= 16) {
|
|
for (i = 8; i--;) t[i] = m.readUInt16LE(i*2+mpos);
|
|
|
|
this.h[0] += t[0] & 0x1fff;
|
|
this.h[1] += ((t[0] >>> 13) | (t[1] << 3)) & 0x1fff;
|
|
this.h[2] += ((t[1] >>> 10) | (t[2] << 6)) & 0x1fff;
|
|
this.h[3] += ((t[2] >>> 7) | (t[3] << 9)) & 0x1fff;
|
|
this.h[4] += ((t[3] >>> 4) | (t[4] << 12)) & 0x1fff;
|
|
this.h[5] += (t[4] >>> 1) & 0x1fff;
|
|
this.h[6] += ((t[4] >>> 14) | (t[5] << 2)) & 0x1fff;
|
|
this.h[7] += ((t[5] >>> 11) | (t[6] << 5)) & 0x1fff;
|
|
this.h[8] += ((t[6] >>> 8) | (t[7] << 8)) & 0x1fff;
|
|
this.h[9] += (t[7] >>> 5) | hibit;
|
|
|
|
for (i = 0, c = 0; i < 10; i++) {
|
|
d[i] = c;
|
|
for (j = 0; j < 10; j++) {
|
|
d[i] += (this.h[j] & 0xffffffff) * ((j <= i) ? this.r[i-j] : (5 * this.r[i+10-j]));
|
|
if (j === 4) {
|
|
c = (d[i] >>> 13);
|
|
d[i] &= 0x1fff;
|
|
}
|
|
}
|
|
c += (d[i] >>> 13);
|
|
d[i] &= 0x1fff;
|
|
}
|
|
c = ((c << 2) + c);
|
|
c += d[0];
|
|
d[0] = ((c & 0xffff) & 0x1fff);
|
|
c = (c >>> 13);
|
|
d[1] += c;
|
|
|
|
for (i = 10; i--;) this.h[i] = d[i];
|
|
|
|
mpos += 16;
|
|
bytes -= 16;
|
|
}
|
|
};
|
|
|
|
Poly1305.prototype.update = function(m) {
|
|
var bytes = m.length;
|
|
var want = 0, i = 0, mpos = 0;
|
|
// var chunk;
|
|
// this.buffer = Buffer.concat([this.buffer, m]);
|
|
// while (this.buffer.length >= 16) {
|
|
// chunk = this.buffer.slice(0, 16);
|
|
// this.buffer = this.buffer.slice(16)
|
|
// this.blocks(chunk, 0, 16);
|
|
// }
|
|
if (this.leftover) {
|
|
want = 16 - this.leftover;
|
|
if (want > bytes)
|
|
want = bytes;
|
|
for (i = want; i--;) {
|
|
this.buffer[this.leftover+i] = m[i+mpos];
|
|
}
|
|
bytes -= want;
|
|
mpos += want;
|
|
this.leftover += want;
|
|
if (this.leftover < 16)
|
|
return this;
|
|
this.blocks(this.buffer, 0, 16);
|
|
this.leftover = 0;
|
|
}
|
|
|
|
if (bytes >= 16) {
|
|
want = (bytes & ~(16 - 1));
|
|
this.blocks(m, mpos, want);
|
|
mpos += want;
|
|
bytes -= want;
|
|
}
|
|
|
|
if (bytes) {
|
|
for (i = bytes; i--;) {
|
|
this.buffer[this.leftover+i] = m[i+mpos];
|
|
}
|
|
this.leftover += bytes;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
Poly1305.prototype.finish = function() {
|
|
var mac = new Buffer(16),
|
|
g = new Uint16Array(10),
|
|
c = 0, mask = 0, f = 0, i = 0;
|
|
if (this.leftover) {
|
|
i = this.leftover;
|
|
this.buffer[i++] = 1;
|
|
for (; i < 16; i++) {
|
|
this.buffer[i] = 0;
|
|
}
|
|
this.finished = 1;
|
|
this.blocks(this.buffer, 0, 16);
|
|
}
|
|
|
|
c = this.h[1] >>> 13;
|
|
this.h[1] &= 0x1fff;
|
|
for (i = 2; i < 10; i++) {
|
|
this.h[i] += c;
|
|
c = this.h[i] >>> 13;
|
|
this.h[i] &= 0x1fff;
|
|
}
|
|
this.h[0] += (c * 5);
|
|
c = this.h[0] >>> 13;
|
|
this.h[0] &= 0x1fff;
|
|
this.h[1] += c;
|
|
c = this.h[1] >>> 13;
|
|
this.h[1] &= 0x1fff;
|
|
this.h[2] += c;
|
|
|
|
g[0] = this.h[0] + 5;
|
|
c = g[0] >>> 13;
|
|
g[0] &= 0x1fff;
|
|
for (i = 1; i < 10; i++) {
|
|
g[i] = this.h[i] + c;
|
|
c = g[i] >>> 13;
|
|
g[i] &= 0x1fff;
|
|
}
|
|
g[9] -= (1 << 13);
|
|
|
|
mask = (g[9] >>> 15) - 1;
|
|
for (i = 10; i--;) g[i] &= mask;
|
|
mask = ~mask;
|
|
for (i = 10; i--;) {
|
|
this.h[i] = (this.h[i] & mask) | g[i];
|
|
}
|
|
|
|
this.h[0] = (this.h[0] ) | (this.h[1] << 13);
|
|
this.h[1] = (this.h[1] >> 3) | (this.h[2] << 10);
|
|
this.h[2] = (this.h[2] >> 6) | (this.h[3] << 7);
|
|
this.h[3] = (this.h[3] >> 9) | (this.h[4] << 4);
|
|
this.h[4] = (this.h[4] >> 12) | (this.h[5] << 1) | (this.h[6] << 14);
|
|
this.h[5] = (this.h[6] >> 2) | (this.h[7] << 11);
|
|
this.h[6] = (this.h[7] >> 5) | (this.h[8] << 8);
|
|
this.h[7] = (this.h[8] >> 8) | (this.h[9] << 5);
|
|
|
|
f = (this.h[0] & 0xffffffff) + this.pad[0];
|
|
this.h[0] = f;
|
|
for (i = 1; i < 8; i++) {
|
|
f = (this.h[i] & 0xffffffff) + this.pad[i] + (f >>> 16);
|
|
this.h[i] = f;
|
|
}
|
|
|
|
for (i = 8; i--;) {
|
|
mac.writeUInt16LE(this.h[i], i*2);
|
|
this.pad[i] = 0;
|
|
}
|
|
for (i = 10; i--;) {
|
|
this.h[i] = 0;
|
|
this.r[i] = 0;
|
|
}
|
|
|
|
return mac;
|
|
}; |