Last active
March 30, 2018 12:46
-
-
Save ZaneHannanAU/60e1781524fada2cf8f7f0babd897043 to your computer and use it in GitHub Desktop.
integrated totp (nodejs)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {fn: {b32_buf, buf_b32, getOTP}} = require('./totp') | |
const givea = fuck => console.log('%s %j', fuck.length.toString().padStart(4), fuck.toString()) | |
const it = process.hrtime() | |
const rt = ([s,ns] = process.hrtime(it)) => console.log('%ss elapsed', (s+ns/1e9).toFixed(9).padStart(12)) | |
rt() | |
const fucks = Buffer.from('Hi there fucks') | |
givea(fucks) | |
rt() | |
const b32fucks = buf_b32(fucks) | |
givea(b32fucks) | |
rt() | |
const ofucks = b32_buf(b32fucks) | |
givea(ofucks) | |
console.assert(ofucks.equals(fucks)) | |
rt() | |
const ok = Buffer.from([0x3d]) | |
givea(ok) | |
rt() | |
const bok = buf_b32(ok) | |
givea(bok) | |
rt() | |
const b32ok = b32_buf(bok) | |
givea(b32ok) | |
console.assert(b32ok.equals(ok)) | |
rt() | |
const crap = getOTP(fucks) | |
givea(crap) | |
rt() | |
const shit = getOTP(fucks) | |
givea(shit) | |
setTimeout(()=>{rt(); givea(getOTP(fucks)); rt()}, 3e4) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0.000192332s elapsed | |
14 "Hi there fucks" | |
0.005373599s elapsed | |
24 "JBUSA5DIMVZGKIDGOVRWW4Y=" | |
0.006357218s elapsed | |
14 "Hi there fucks" | |
0.007532192s elapsed | |
1 "=" | |
0.008020879s elapsed | |
8 "HU======" | |
0.008177638s elapsed | |
1 "=" | |
0.008350557s elapsed | |
6 "122610" | |
0.009628935s elapsed | |
6 "122610" | |
30.043018793s elapsed | |
6 "465683" | |
30.044405246s elapsed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto') | |
const {b32c, b256} = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567').reduce((o,c,i)=>{ | |
o.b32c[c] = i; | |
o.b32c[c.codePointAt(0)] = i; | |
o.b256[i] = c.codePointAt(0); | |
return o; | |
}, {b32c: Object.create(null), b256: Buffer.alloc(33)}) | |
// console.log(b32c, c32b) | |
const _31 = Math.pow(2,31)-1 // shorthand to fill crap | |
const b32_buf = b32 => { | |
let B32 = b32 | |
let ec = B32.indexOf('=') > -1 ? B32.length - B32.indexOf('=') : 0 | |
let v1, v2, v3, v4, v5, v6, v7, v8, | |
buf = Buffer.allocUnsafe(Math.abs(5 * Math.ceil(B32.length / 8) - ec)), | |
i = 0, | |
idx = 0, | |
len = b32.indexOf('='), | |
cnt = len >> 3 << 3, | |
rem = len - cnt | |
// 8 chars are 5 bytes | |
while (i < cnt) { | |
v1 = b32c[B32[i++]]; | |
v2 = b32c[B32[i++]]; | |
v3 = b32c[B32[i++]]; | |
v4 = b32c[B32[i++]]; | |
v5 = b32c[B32[i++]]; | |
v6 = b32c[B32[i++]]; | |
v7 = b32c[B32[i++]]; | |
v8 = b32c[B32[i++]]; | |
buf[idx++] = (v1 << 3 | v2 >>> 2) & 255; | |
buf[idx++] = (v2 << 6 | v3 << 1 | v4 >>> 4) & 255; | |
buf[idx++] = (v4 << 4 | v5 >>> 1) & 255; | |
buf[idx++] = (v5 << 7 | v6 << 2 | v7 >>> 3) & 255; | |
buf[idx++] = (v7 << 5 | v8) & 255; | |
}; | |
switch (rem) { | |
case 2: | |
v1 = b32c[B32[i++]]; | |
v2 = b32c[B32[i++]]; | |
buf[idx++] = (v1 << 3 | v2 >>> 2) & 255; | |
break; | |
case 4: | |
v1 = b32c[B32[i++]]; | |
v2 = b32c[B32[i++]]; | |
v3 = b32c[B32[i++]]; | |
v4 = b32c[B32[i++]]; | |
buf[idx++] = (v1 << 3 | v2 >>> 2) & 255; | |
buf[idx++] = (v2 << 6 | v3 << 1 | v4 >>> 4) & 255; | |
break; | |
case 5: | |
v1 = b32c[B32[i++]]; | |
v2 = b32c[B32[i++]]; | |
v3 = b32c[B32[i++]]; | |
v4 = b32c[B32[i++]]; | |
v5 = b32c[B32[i++]]; | |
buf[idx++] = (v1 << 3 | v2 >>> 2) & 255; | |
buf[idx++] = (v2 << 6 | v3 << 1 | v4 >>> 4) & 255; | |
buf[idx++] = (v4 << 4 | v5 >>> 1) & 255; | |
break; | |
case 7: | |
v1 = b32c[B32[i++]]; | |
v2 = b32c[B32[i++]]; | |
v3 = b32c[B32[i++]]; | |
v4 = b32c[B32[i++]]; | |
v5 = b32c[B32[i++]]; | |
v6 = b32c[B32[i++]]; | |
v7 = b32c[B32[i++]]; | |
buf[idx++] = (v1 << 3 | v2 >>> 2) & 255; | |
buf[idx++] = (v2 << 6 | v3 << 1 | v4 >>> 4) & 255; | |
buf[idx++] = (v4 << 4 | v5 >>> 1) & 255; | |
buf[idx++] = (v5 << 7 | v6 << 2 | v7 >>> 3) & 255; | |
break; | |
}; | |
return buf; | |
}; | |
const buf_b32 = buf => { | |
let v1, v2, v3, v4, v5, | |
b32 = Buffer.allocUnsafe(8 * Math.ceil(buf.length / 5)), | |
i = 0, | |
idx = 0, | |
len = buf.length, | |
cnt = Math.floor(len / 5) * 5, | |
rem = len - cnt | |
while (i < cnt) { | |
v1 = buf[i++]; | |
v2 = buf[i++]; | |
v3 = buf[i++]; | |
v4 = buf[i++]; | |
v5 = buf[i++]; | |
b32.writeInt32BE( | |
b256[v1 >>> 3] << 24 | |
| b256[(v1 << 2 | v2 >>> 6) & 31] << 16 | |
| b256[(v2 >>> 1) & 31] << 8 | |
| b256[(v2 << 4 | v3 >>> 4) & 31], | |
4 * idx++ | |
); | |
b32.writeInt32BE( | |
b256[(v3 << 1 | v4 >>> 7) & 31] << 24 | |
| b256[(v4 >>> 2) & 31] << 16 | |
| b256[(v4 << 3 | v5 >>> 5) & 31] << 8 | |
| b256[v5 & 31], | |
4 * idx++ | |
); | |
}; | |
switch (rem) { | |
case 1: | |
v1 = buf[i++]; | |
b32.writeInt32BE(b256[v1 >>> 3] << 24 | b256[(v1 << 2) & 31] << 16 | 0x3d3d, 4 * idx++); | |
b32.writeInt32BE(0x3d3d3d3d, 4 * idx++); | |
break; | |
case 2: | |
v1 = buf[i++]; | |
v2 = buf[i++]; | |
b32.writeInt32BE( | |
b256[v1 >>> 3] << 24 | |
| b256[(v1 << 2 | v2 >>> 6) & 31] << 16 | |
| b256[(v2 >>> 1) & 31] << 8 | |
| b256[(v2 << 4) & 31], | |
4 * idx++ | |
); | |
b32.writeInt32BE(0x3d3d3d3d, 4 * idx++); | |
break; | |
case 3: | |
v1 = buf[i++]; | |
v2 = buf[i++]; | |
v3 = buf[i++]; | |
b32.writeInt32BE( | |
b256[v1 >>> 3] << 24 | |
| b256[(v1 << 2 | v2 >>> 6) & 31] << 16 | |
| b256[(v2 >>> 1) & 31] << 8 | |
| b256[(v2 << 4 | v3 >>> 4) & 31], | |
4 * idx++ | |
); | |
b32.writeInt32BE( | |
b256[(v3 << 1) & 31] << 24 | 0x3d3d3d, | |
4 * idx++ | |
); | |
break; | |
case 4: | |
v1 = buf[i++]; | |
v2 = buf[i++]; | |
v3 = buf[i++]; | |
v4 = buf[i++]; | |
b32.writeInt32BE( | |
b256[v1 >>> 3] << 24 | |
| b256[(v1 << 2 | v2 >>> 6) & 31] << 16 | |
| b256[(v2 >>> 1) & 31] << 8 | |
| b256[(v2 << 4 | v3 >>> 4) & 31], | |
4 * idx++ | |
); | |
b32.writeInt32BE( | |
b256[(v3 << 1 | v4 >>> 7) & 31] << 24 | |
| b256[(v4 >>> 2) & 31] << 16 | |
| b256[(v4 << 3) & 31] << 8 | |
| 0x3d, | |
4 * idx++ | |
); | |
break; | |
}; | |
return b32; | |
}; | |
const getOTP = (secret, len = 6, T0 = 0, TI = 30) => { | |
const TC = Math.floor((Math.round(Date.now() / 1e3) - T0) / TI) | |
.toString(16) | |
.padStart(16, '0'); | |
const TOTP = crypto.createHmac('sha1', secret) | |
.update(TC, 'hex') | |
.digest() | |
.readInt32BE(16) & _31; | |
return String(TOTP % Math.pow(10, len)).padStart(6,'0'); | |
}; | |
const TOTP = { | |
constants: {b32c, b256, _31}, | |
fn: {b32_buf, buf_b32, getOTP} | |
}; | |
module.exports = TOTP; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment