obniz
Version:
obniz sdk for javascript
157 lines (156 loc) • 4.92 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @packageDocumentation
*
* @ignore
*/
const crypto_1 = __importDefault(require("crypto"));
/**
* @ignore
*/
const r = () => {
return crypto_1.default.randomBytes(16);
};
/**
* @ignore
*/
const c1 = (k, _r, pres, preq, iat, ia, rat, ra) => {
const p1 = Buffer.concat([iat, rat, preq, pres]);
const p2 = Buffer.concat([ra, ia, Buffer.from('00000000', 'hex')]);
let res = xor(_r, p1);
res = e(k, res);
res = xor(res, p2);
res = e(k, res);
return res;
};
const s1 = (k, r1, r2) => {
return e(k, Buffer.concat([r2.slice(0, 8), r1.slice(0, 8)]));
};
const e = (key, data) => {
key = swap(key);
data = swap(data);
const cipher = crypto_1.default.createCipheriv('aes-128-ecb', key, '');
cipher.setAutoPadding(false);
return swap(Buffer.concat([cipher.update(data), cipher.final()]));
};
const xor = (b1, b2) => {
const result = Buffer.alloc(b1.length);
for (let i = 0; i < b1.length; i++) {
result[i] = b1[i] ^ b2[i];
}
return result;
};
const swap = (input) => {
const output = Buffer.alloc(input.length);
for (let i = 0; i < output.length; i++) {
output[i] = input[input.length - i - 1];
}
return output;
};
const emptyBuffer = Buffer.alloc(0);
const AESCMAC = (key, message) => {
const zero = Buffer.alloc(16);
const aes = crypto_1.default.createCipheriv('AES-128-ECB', key, emptyBuffer);
const L = aes.update(zero);
if (leftShift128(L)) {
L[15] ^= 0x87;
}
let flag = true;
if (message.length === 0 || message.length % 16 !== 0) {
if (leftShift128(L)) {
L[15] ^= 0x87;
}
flag = false;
}
let X = zero;
const n = (message.length + 15) >>> 4;
let processed = 0;
for (let i = 0; i < n - 1; i++) {
X = aes.update(xor(X, message.slice(processed, processed + 16)));
processed += 16;
}
const last = Buffer.alloc(16);
message.copy(last, 0, processed);
if (!flag) {
last[message.length % 16] = 0x80;
}
return aes.update(xor(xor(X, L), last));
};
const leftShift128 = (v) => {
let carry = 0;
for (let i = 15; i >= 0; --i) {
const nextCarry = v[i] >> 7;
v[i] = (v[i] << 1) | carry;
carry = nextCarry;
}
return carry;
};
const f4 = (U, V, X, Z) => {
return AESCMAC(Buffer.from(X).reverse(), Buffer.concat([Buffer.from([Z]), V, U]).reverse()).reverse();
};
const f5 = (W, N1, N2, A1, A2) => {
const SALT = Buffer.from('6C888391AAF5A53860370BDB5A6083BE', 'hex');
const T = AESCMAC(SALT, Buffer.from(W).reverse());
const v = Buffer.concat([
Buffer.from('btle', 'utf8'),
Buffer.from(N1).reverse(),
Buffer.from(N2).reverse(),
Buffer.from(A1).reverse(),
Buffer.from(A2).reverse(),
Buffer.from([1, 0]),
]);
const macKey = AESCMAC(T, Buffer.concat([Buffer.from([0]), v])).reverse();
const ltk = AESCMAC(T, Buffer.concat([Buffer.from([1]), v])).reverse();
return [macKey, ltk];
};
const f6 = (W, N1, N2, R, IOcap, A1, A2) => {
return AESCMAC(Buffer.from(W).reverse(), Buffer.concat([A2, A1, IOcap, R, N2, N1]).reverse()).reverse();
};
const g2 = (U, V, X, Y) => {
return AESCMAC(Buffer.from(X).reverse(), Buffer.concat([Y, V, U]).reverse()).readUInt32BE(12);
};
const createECDHKey = () => {
const ecdh = crypto_1.default.createECDH('prime256v1');
ecdh.generateKeys();
return {
x: ecdh.getPublicKey().slice(1, 33).reverse(),
y: ecdh.getPublicKey().slice(33, 65).reverse(),
ecdh,
};
};
const generateLtkEaEb = (ecdh, peerPublicKey, ia, iat, ra, rat, initRandomValue, rspRandomValue, userPasskey, maxKeySize, IOCapA, IOCapB) => {
const userPasskeyBuffer = Buffer.alloc(16);
userPasskeyBuffer.writeUInt32LE(userPasskey, 0);
let sharedSecret = null;
const buf = Buffer.alloc(65);
buf[0] = 0x04;
for (let i = 0; i < 32; i++) {
buf[1 + i] = peerPublicKey.x[31 - i];
buf[33 + i] = peerPublicKey.y[31 - i];
}
sharedSecret = ecdh.computeSecret(buf).reverse();
const A = Buffer.concat([ia, iat]);
const B = Buffer.concat([ra, rat]);
const keys = f5(sharedSecret, initRandomValue, rspRandomValue, A, B);
const macKey = keys[0];
const ltk = keys[1].slice(0, maxKeySize);
const Ea = f6(macKey, initRandomValue, rspRandomValue, userPasskeyBuffer, IOCapA, A, B);
const Eb = f6(macKey, rspRandomValue, initRandomValue, userPasskeyBuffer, IOCapB, B, A);
return { ltk, Ea, Eb };
};
exports.default = {
r,
c1,
s1,
e,
f4,
f5,
f6,
createECDHKey,
randomBytes: crypto_1.default.randomBytes,
generateLtkEaEb,
};