UNPKG

iobroker.plenticore-g3

Version:

Adapter to communicate with a KOSTAL Plenticore Plus via local network (non-modbus)

679 lines (664 loc) 21.5 kB
// file borrowed from: https://github.com/pixcept/ioBroker.plenticore/blob/master/lib/kostal.js 'use strict'; var KOSTAL = { getNonce: function () { return KOSTAL.base64.fromBits(KOSTAL.random.randomWords(3)); }, hash: { sha256: function (t) { this.b[0] || this.O(), t ? ((this.F = t.F.slice(0)), (this.A = t.A.slice(0)), (this.l = t.l)) : this.reset(); }, hmac: function (t, e) { this.W = e = e || KOSTAL.hash.sha256; var n, r = [[], []], i = e.prototype.blockSize / 32; for (this.w = [new e(), new e()], t.length > i && (t = e.hash(t)), n = 0; n < i; n++) { r[0][n] = 909522486 ^ t[n]; r[1][n] = 1549556828 ^ t[n]; } this.w[0].update(r[0]); this.w[1].update(r[1]); this.R = new e(this.w[0]); }, }, pbkdf2: function (t, e, n, r, i) { n = n || 10000; if (0 > r || 0 > n) { throw new KOSTAL.exception.invalid('invalid params'); } 'string' === typeof t && (t = KOSTAL.utf8String.toBits(t)); 'string' === typeof e && (e = KOSTAL.utf8String.toBits(e)); t = new (i = i || KOSTAL.hash.hmac)(t); var a, s, u, c, l = [], d = KOSTAL.bitArray; for (c = 1; 32 * l.length < (r || 1); c++) { for (i = a = t.encrypt(d.concat(e, [c])), s = 1; s < n; s++) { for (a = t.encrypt(a), u = 0; u < a.length; u++) { i[u] ^= a[u]; } } l = l.concat(i); } return r && (l = d.clamp(l, r)), l; }, base64: { B: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', fromBits: function (t, e, n) { var r = '', i = 0, a = KOSTAL.base64.B, s = 0, u = KOSTAL.bitArray.bitLength(t); for (n && (a = `${a.substr(0, 62)}-_`), n = 0; 6 * r.length < u; ) { r += a.charAt((s ^ (t[n] >>> i)) >>> 26); 6 > i ? ((s = t[n] << (6 - i)), (i += 26), n++) : ((s <<= 6), (i -= 6)); } for (; 3 & r.length && !e; ) { r += '='; } return r; }, toBits: function (t, e) { t = t.replace(/\s|=/g, ''); var n, r, i = [], a = 0, s = KOSTAL.base64.B, u = 0; for (e && (s = `${s.substr(0, 62)}-_`), n = 0; n < t.length; n++) { if (0 > (r = s.indexOf(t.charAt(n)))) { throw new KOSTAL.exception.invalid('no base64 string!'); } 26 < a ? ((a -= 26), i.push(u ^ (r >>> a)), (u = r << (32 - a))) : (u ^= r << (32 - (a += 6))); } 56 & a && i.push(KOSTAL.bitArray.partial(56 & a, u, 1)); return i; }, }, bitArray: { bitSlice: function (t, e, n) { t = KOSTAL.bitArray.$(t.slice(e / 32), 32 - (31 & e)).slice(1); return void 0 === n ? t : KOSTAL.bitArray.clamp(t, n - e); }, extract: function (t, e, n) { var r = Math.floor((-e - n) & 31); return ( (-32 & ((e + n - 1) ^ e) ? (t[(e / 32) | 0] << (32 - r)) ^ (t[(e / 32 + 1) | 0] >>> r) : t[(e / 32) | 0] >>> r) & ((1 << n) - 1) ); }, concat: function (t, e) { if (0 === t.length || 0 === e.length) { return t.concat(e); } var n = t[t.length - 1], r = KOSTAL.bitArray.getPartial(n); return 32 === r ? t.concat(e) : KOSTAL.bitArray.$(e, r, 0 | n, t.slice(0, t.length - 1)); }, bitLength: function (t) { var e = t.length; return 0 === e ? 0 : 32 * (e - 1) + KOSTAL.bitArray.getPartial(t[e - 1]); }, clamp: function (t, e) { if (32 * t.length < e) { return t; } var n = (t = t.slice(0, Math.ceil(e / 32))).length; e &= 31; 0 < n && e && (t[n - 1] = KOSTAL.bitArray.partial(e, t[n - 1] & (2147483648 >> (e - 1)), 1)); return t; }, partial: function (t, e, n) { return 32 === t ? e : (n ? 0 | e : e << (32 - t)) + 1099511627776 * t; }, getPartial: function (t) { return Math.round(t / 1099511627776) || 32; }, equal: function (t, e) { if (KOSTAL.bitArray.bitLength(t) !== KOSTAL.bitArray.bitLength(e)) { return false; } var n, r = 0; for (n = 0; n < t.length; n++) { r |= t[n] ^ e[n]; } return 0 === r; }, $: function (t, e, n, r) { var i; for (i = 0, void 0 === r && (r = []); 32 <= e; e -= 32) { r.push(n); n = 0; } if (0 === e) { return r.concat(t); } for (i = 0; i < t.length; i++) { r.push(n | (t[i] >>> e)); n = t[i] << (32 - e); } i = t.length ? t[t.length - 1] : 0; t = KOSTAL.bitArray.getPartial(i); r.push(KOSTAL.bitArray.partial((e + t) & 31, 32 < e + t ? n : r.pop(), 1)); return r; }, i: function (t, e) { return [t[0] ^ e[0], t[1] ^ e[1], t[2] ^ e[2], t[3] ^ e[3]]; }, byteswapM: function (t) { var e, n; for (e = 0; e < t.length; ++e) { n = t[e]; t[e] = (n >>> 24) | ((n >>> 8) & 65280) | ((65280 & n) << 8) | (n << 24); } return t; }, }, encrypt: function (l, n) { var u = new KOSTAL.cipher.aes(l), t = KOSTAL.random.randomWords(4), e = KOSTAL.gcm.encrypt(u, KOSTAL.utf8String.toBits(n), t); return { iv: t, tag: KOSTAL.bitArray.bitSlice(e, KOSTAL.bitArray.bitLength(e) - 128), ciphertext: KOSTAL.bitArray.clamp(e, KOSTAL.bitArray.bitLength(e) - 128), }; }, cipher: { aes: function (t) { this.s[0][0][0] || this.O(); var e, n, r, i, a = this.s[0][4], s = this.s[1], u = 1; if (4 !== (e = t.length) && 6 !== e && 8 !== e) { throw new KOSTAL.exception.invalid('invalid aes key size'); } for (this.b = [(r = t.slice(0)), (i = [])], t = e; t < 4 * e + 28; t++) { n = r[t - 1]; (0 === t % e || (8 === e && 4 === t % e)) && ((n = (a[n >>> 24] << 24) ^ (a[(n >> 16) & 255] << 16) ^ (a[(n >> 8) & 255] << 8) ^ a[255 & n]), 0 === t % e && ((n = (n << 8) ^ (n >>> 24) ^ (u << 24)), (u = (u << 1) ^ (283 * (u >> 7))))); r[t] = r[t - e] ^ n; } for (e = 0; t; e++, t--) { n = r[3 & e ? t : t - 4]; i[e] = 4 >= t || 4 > e ? n : s[0][a[n >>> 24]] ^ s[1][a[(n >> 16) & 255]] ^ s[2][a[(n >> 8) & 255]] ^ s[3][a[255 & n]]; } }, }, gcm: { name: 'gcm', encrypt: function (t, e, n, r, i) { var a = e.slice(0); return ( (e = KOSTAL.bitArray), (r = r || []), (t = KOSTAL.gcm.C(true, t, a, r, n, i || 128)), e.concat(t.data, t.tag) ); }, decrypt: function (t, e, n, r, i) { var a = e.slice(0), s = KOSTAL.bitArray, u = s.bitLength(a); i = i || 128; r = r || []; i <= u ? ((e = s.bitSlice(a, u - i)), (a = s.bitSlice(a, 0, u - i))) : ((e = a), (a = [])); t = KOSTAL.gcm.C(false, t, a, r, n, i); if (!s.equal(t.tag, e)) { throw new KOSTAL.exception.corrupt('unmatchin tag'); } return t.data; }, ka: function (t, e) { var n, r, i, a, s, u = KOSTAL.bitArray.i; for (i = [0, 0, 0, 0], a = e.slice(0), n = 0; 128 > n; n++) { (r = 0 !== (t[Math.floor(n / 32)] & (1 << (31 - (n % 32))))) && (i = u(i, a)); s = 0 !== (1 & a[3]); for (r = 3; 0 < r; r--) { a[r] = (a[r] >>> 1) | ((1 & a[r - 1]) << 31); } (a[0] >>>= 1), s && (a[0] ^= -520093696); } return i; }, j: function (t, e, n) { var r, i = n.length; for (e = e.slice(0), r = 0; r < i; r += 4) { e[0] ^= 4294967295 & n[r]; e[1] ^= 4294967295 & n[r + 1]; e[2] ^= 4294967295 & n[r + 2]; e[3] ^= 4294967295 & n[r + 3]; e = KOSTAL.gcm.ka(e, t); } return e; }, C: function (t, e, n, r, i, a) { var s, u, c, l, d, h, f, p, _ = KOSTAL.bitArray; for ( h = n.length, f = _.bitLength(n), p = _.bitLength(r), u = _.bitLength(i), s = e.encrypt([0, 0, 0, 0]), 96 === u ? ((i = i.slice(0)), (i = _.concat(i, [1]))) : ((i = KOSTAL.gcm.j(s, [0, 0, 0, 0], i)), (i = KOSTAL.gcm.j(s, i, [0, 0, Math.floor(u / 4294967296), 4294967295 & u]))), u = KOSTAL.gcm.j(s, [0, 0, 0, 0], r), d = i.slice(0), r = u.slice(0), t || (r = KOSTAL.gcm.j(s, u, n)), l = 0; l < h; l += 4 ) { d[3]++; c = e.encrypt(d); n[l] ^= c[0]; n[l + 1] ^= c[1]; n[l + 2] ^= c[2]; n[l + 3] ^= c[3]; } n = _.clamp(n, f); t && (r = KOSTAL.gcm.j(s, u, n)); t = [Math.floor(p / 4294967296), 4294967295 & p, Math.floor(f / 4294967296), 4294967295 & f]; r = KOSTAL.gcm.j(s, r, t); c = e.encrypt(i); r[0] ^= c[0]; r[1] ^= c[1]; r[2] ^= c[2]; r[3] ^= c[3]; return { tag: _.bitSlice(r, 0, a), data: n, }; }, }, exception: { corrupt: function (t) { this.toString = function () { return `CORRUPT: ${this.message}`; }; this.message = t; }, invalid: function (t) { this.toString = function () { return `INVALID: ${this.message}`; }; this.message = t; }, }, utf8String: { fromBits: function (t) { var e, n, r = '', i = KOSTAL.bitArray.bitLength(t); for (e = 0; e < i / 8; e++) { if (0 === (3 & e)) { n = t[e / 4]; } r += String.fromCharCode(((n >>> 8) >>> 8) >>> 8); n <<= 8; } return decodeURIComponent(escape(r)); }, toBits: function (t) { t = unescape(encodeURIComponent(t)); var e, n = [], r = 0; for (e = 0; e < t.length; e++) { r = (r << 8) | t.charCodeAt(e); if (3 === (3 & e)) { n.push(r); r = 0; } } 3 & e && n.push(KOSTAL.bitArray.partial(8 * (3 & e), r)); return n; }, }, fa: function (t, e) { var n, r, o, i = t.F, a = t.b, s = i[0], u = i[1], c = i[2], l = i[3], d = i[4], h = i[5], f = i[6], p = i[7]; for (n = 0; 64 > n; n++) { 16 > n ? (r = e[n]) : ((r = e[(n + 1) & 15]), (o = e[(n + 14) & 15]), (r = e[15 & n] = (((r >>> 7) ^ (r >>> 18) ^ (r >>> 3) ^ (r << 25) ^ (r << 14)) + ((o >>> 17) ^ (o >>> 19) ^ (o >>> 10) ^ (o << 15) ^ (o << 13)) + e[15 & n] + e[(n + 9) & 15]) | 0)); r = r + p + ((d >>> 6) ^ (d >>> 11) ^ (d >>> 25) ^ (d << 26) ^ (d << 21) ^ (d << 7)) + (f ^ (d & (h ^ f))) + a[n]; p = f; f = h; h = d; d = (l + r) | 0; l = c; c = u; s = (r + (((u = s) & c) ^ (l & (u ^ c))) + ((u >>> 2) ^ (u >>> 13) ^ (u >>> 22) ^ (u << 30) ^ (u << 19) ^ (u << 10))) | 0; } i[0] = (i[0] + s) | 0; i[1] = (i[1] + u) | 0; i[2] = (i[2] + c) | 0; i[3] = (i[3] + l) | 0; i[4] = (i[4] + d) | 0; i[5] = (i[5] + h) | 0; i[6] = (i[6] + f) | 0; i[7] = (i[7] + p) | 0; }, c: function (t) { t.b = this.l(t).concat(this.l(t)); t.L = new KOSTAL.cipher.aes(t.b); }, l: function (t) { for (var e = 0; 4 > e && ((t.h[e] = (t.h[e] + 1) | 0), !t.h[e]); e++) { null; } return t.L.encrypt(t.h); }, i: function (t, e, n) { if (4 !== e.length) { throw new this.exception.invalid('invalid aes block size'); } var r = t.b[n], i = e[0] ^ r[0], a = e[n ? 3 : 1] ^ r[1], s = e[2] ^ r[2]; e = e[n ? 1 : 3] ^ r[3]; var u, c, l, d, h = r.length / 4 - 2, f = 4, p = [0, 0, 0, 0]; t = (u = t.s[n])[0]; var _ = u[1], m = u[2], y = u[3], v = u[4]; for (d = 0; d < h; d++) { u = t[i >>> 24] ^ _[(a >> 16) & 255] ^ m[(s >> 8) & 255] ^ y[255 & e] ^ r[f]; c = t[a >>> 24] ^ _[(s >> 16) & 255] ^ m[(e >> 8) & 255] ^ y[255 & i] ^ r[f + 1]; l = t[s >>> 24] ^ _[(e >> 16) & 255] ^ m[(i >> 8) & 255] ^ y[255 & a] ^ r[f + 2]; e = t[e >>> 24] ^ _[(i >> 16) & 255] ^ m[(a >> 8) & 255] ^ y[255 & s] ^ r[f + 3]; f += 4; i = u; a = c; s = l; } for (d = 0; 4 > d; d++) { p[n ? 3 & -d : d] = (v[i >>> 24] << 24) ^ (v[(a >> 16) & 255] << 16) ^ (v[(s >> 8) & 255] << 8) ^ v[255 & e] ^ r[f++]; u = i; i = a; a = s; s = e; e = u; } return p; }, }; KOSTAL.hash.hmac.prototype.encrypt = KOSTAL.hash.hmac.prototype.mac = function (t) { if (this.aa) { throw new KOSTAL.exception.invalid('encrypt on already updated hmac called!'); } this.update(t); return this.digest(t); }; KOSTAL.hash.hmac.prototype.reset = function () { this.R = new this.W(this.w[0]); this.aa = false; }; KOSTAL.hash.hmac.prototype.update = function (t) { this.aa = true; this.R.update(t); }; KOSTAL.hash.hmac.prototype.digest = function () { var t = this.R.finalize(); t = new this.W(this.w[1]).update(t).finalize(); this.reset(); return t; }; KOSTAL.hash.sha256.hash = function (t) { return new KOSTAL.hash.sha256().update(t).finalize(); }; KOSTAL.hash.sha256.prototype = { blockSize: 512, reset: function () { this.F = this.Y.slice(0); this.A = []; this.l = 0; return this; }, update: function (t) { 'string' === typeof t && (t = KOSTAL.utf8String.toBits(t)); var e, n = (this.A = KOSTAL.bitArray.concat(this.A, t)); e = this.l; if (9007199254740991 < (t = this.l = e + KOSTAL.bitArray.bitLength(t))) { throw new KOSTAL.exception.invalid('Cannot hash more than 2^53 - 1 bits'); } if ('undefined' !== typeof Uint32Array) { var r = new Uint32Array(n), i = 0; for (e = 512 + e - ((512 + e) & 511); e <= t; e += 512) { KOSTAL.fa(this, r.subarray(16 * i, 16 * (i + 1))); i += 1; } n.splice(0, 16 * i); } else { for (e = 512 + e - ((512 + e) & 511); e <= t; e += 512) { KOSTAL.fa(this, n.splice(0, 16)); } } return this; }, finalize: function () { var t, e = this.A, n = this.F; for (t = (e = KOSTAL.bitArray.concat(e, [KOSTAL.bitArray.partial(1, 1)])).length + 2; 15 & t; t++) { e.push(0); } for (e.push(Math.floor(this.l / 4294967296)), e.push(0 | this.l); e.length; ) { KOSTAL.fa(this, e.splice(0, 16)); } this.reset(); return n; }, Y: [], b: [], O: function () { function t(t) { return (4294967296 * (t - Math.floor(t))) | 0; } for (var e, n, r = 0, o = 2; 64 > r; o++) { for (n = true, e = 2; e * e <= o; e++) { if (0 === o % e) { n = false; break; } } n && (8 > r && (this.Y[r] = t(Math.pow(o, 0.5))), (this.b[r] = t(Math.pow(o, 1 / 3))), r++); } }, }; KOSTAL.random = { c: [new KOSTAL.hash.sha256()], m: [0], P: 0, H: {}, N: 0, U: {}, Z: 0, f: 0, o: 0, ha: 0, b: [0, 0, 0, 0, 0, 0, 0, 0], h: [0, 0, 0, 0], L: void 0, M: 6, D: false, K: { progress: {}, seeded: {}, }, u: 0, ga: 0, I: 1, J: 2, ca: 65536, T: [0, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024], da: 30000, ba: 80, randomWords: function (t) { var n, r = [], i = [], a, s = 0; for (this.Z = r[0] = new Date().valueOf() + this.da, a = 0; 16 > a; a++) { r.push((4294967296 * Math.random()) | 0); } for ( a = 0; a < this.c.length && ((r = r.concat(this.c[a].finalize())), (s += this.m[a]), (this.m[a] = 0), n || !(this.P & (1 << a))); a++ ) { null; } for ( this.P >= 1 << this.c.length && (this.c.push(new KOSTAL.hash.sha256()), this.m.push(0)), this.f -= s, s > this.o && (this.o = s), this.P++, this.b = KOSTAL.hash.sha256.hash(this.b.concat(r)), this.L = new KOSTAL.cipher.aes(this.b), n = 0; 4 > n && ((this.h[n] = (this.h[n] + 1) | 0), !this.h[n]); n++ ) { null; } for (n = 0; n < t; n += 4) { if (0 === (n + 1) % this.ca) { KOSTAL.c(this); } r = KOSTAL.l(this); i.push(r[0], r[1], r[2], r[3]); } KOSTAL.c(this); return i.slice(0, t); }, }; KOSTAL.cipher.aes.prototype = { encrypt: function (t) { return KOSTAL.i(this, t, 0); }, decrypt: function (t) { return KOSTAL.i(this, t, 1); }, s: [ [[], [], [], [], []], [[], [], [], [], []], ], O: function () { var t, e, n, r, o, i, a, s = this.s[0], u = this.s[1], c = s[4], l = u[4], d = [], h = []; for (t = 0; 256 > t; t++) { h[(d[t] = (t << 1) ^ (283 * (t >> 7))) ^ t] = t; } for (e = n = 0; !c[e]; e ^= r || 1, n = h[n] || 1) { for ( i = ((i = n ^ (n << 1) ^ (n << 2) ^ (n << 3) ^ (n << 4)) >> 8) ^ (255 & i) ^ 99, c[e] = i, l[i] = e, a = (16843009 * (o = d[(t = d[(r = d[e])])])) ^ (65537 * t) ^ (257 * r) ^ (16843008 * e), o = (257 * d[i]) ^ (16843008 * i), t = 0; 4 > t; t++ ) { s[t][e] = o = (o << 24) ^ (o >>> 8); u[t][i] = a = (a << 24) ^ (a >>> 8); } } for (t = 0; 5 > t; t++) { s[t] = s[t].slice(0); u[t] = u[t].slice(0); } }, }; module.exports = { KOSTAL: KOSTAL, };