UNPKG

obniz

Version:

obniz sdk for javascript

129 lines (128 loc) 5.18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Smp = void 0; /** * @packageDocumentation * * @ignore */ const eventemitter3_1 = __importDefault(require("eventemitter3")); const bleHelper_1 = __importDefault(require("../../bleHelper")); const crypto_1 = __importDefault(require("../common/crypto")); const mgmt_1 = require("./mgmt"); const smp_1 = require("../common/smp"); /** * @ignore */ class Smp extends eventemitter3_1.default { constructor(aclStream, localAddressType, localAddress, remoteAddressType, remoteAddress, hciProtocol) { super(); this._aclStream = aclStream; this._mgmt = new mgmt_1.Mgmt(hciProtocol); this._iat = Buffer.from([remoteAddressType === 'random' ? 0x01 : 0x00]); this._ia = bleHelper_1.default.hex2reversedBuffer(remoteAddress, ':'); this._rat = Buffer.from([localAddressType === 'random' ? 0x01 : 0x00]); this._ra = bleHelper_1.default.hex2reversedBuffer(localAddress, ':'); this._stk = null; this._random = null; this._diversifier = null; this.onAclStreamDataBinded = this.onAclStreamData.bind(this); this.onAclStreamEncryptChangeBinded = this.onAclStreamEncryptChange.bind(this); this.onAclStreamLtkNegReplyBinded = this.onAclStreamLtkNegReply.bind(this); this.onAclStreamEndBinded = this.onAclStreamEnd.bind(this); this._aclStream.on('data', this.onAclStreamDataBinded); this._aclStream.on('encryptChange', this.onAclStreamEncryptChangeBinded); this._aclStream.on('ltkNegReply', this.onAclStreamLtkNegReplyBinded); this._aclStream.on('end', this.onAclStreamEndBinded); } onAclStreamData(cid, data) { if (cid !== smp_1.SMP.CID) { return; } const code = data.readUInt8(0); if (smp_1.SMP.PAIRING_REQUEST === code) { this.handlePairingRequest(data); } else if (smp_1.SMP.PAIRING_CONFIRM === code) { this.handlePairingConfirm(data); } else if (smp_1.SMP.PAIRING_RANDOM === code) { this.handlePairingRandom(data); } else if (smp_1.SMP.PAIRING_FAILED === code) { this.handlePairingFailed(data); } } onAclStreamEncryptChange(encrypted) { if (encrypted) { if (this._stk && this._diversifier && this._random) { this.write(Buffer.concat([Buffer.from([smp_1.SMP.ENCRYPT_INFO]), this._stk])); this.write(Buffer.concat([ Buffer.from([smp_1.SMP.MASTER_IDENT]), this._diversifier, this._random, ])); } } } onAclStreamLtkNegReply() { this.write(Buffer.from([smp_1.SMP.PAIRING_FAILED, smp_1.SMP.UNSPECIFIED])); this.emit('fail'); } onAclStreamEnd() { this._aclStream.removeListener('data', this.onAclStreamDataBinded); this._aclStream.removeListener('encryptChange', this.onAclStreamEncryptChangeBinded); this._aclStream.removeListener('ltkNegReply', this.onAclStreamLtkNegReplyBinded); this._aclStream.removeListener('end', this.onAclStreamEndBinded); } handlePairingRequest(data) { this._preq = data; this._pres = Buffer.from([ smp_1.SMP.PAIRING_RESPONSE, 0x03, 0x00, 0x01, 0x10, 0x00, 0x01, // Responder key distribution: EncKey ]); this.write(this._pres); } handlePairingConfirm(data) { this._pcnf = data; this._tk = Buffer.from('00000000000000000000000000000000', 'hex'); this._r = crypto_1.default.r(); this.write(Buffer.concat([ Buffer.from([smp_1.SMP.PAIRING_CONFIRM]), crypto_1.default.c1(this._tk, this._r, this._pres, this._preq, this._iat, this._ia, this._rat, this._ra), ])); } handlePairingRandom(data) { const r = data.slice(1); const pcnf = Buffer.concat([ Buffer.from([smp_1.SMP.PAIRING_CONFIRM]), crypto_1.default.c1(this._tk, r, this._pres, this._preq, this._iat, this._ia, this._rat, this._ra), ]); if (this._pcnf.toString('hex') === pcnf.toString('hex')) { this._diversifier = Buffer.from('0000', 'hex'); this._random = Buffer.from('0000000000000000', 'hex'); this._stk = crypto_1.default.s1(this._tk, this._r, r); this._mgmt.addLongTermKey(this._ia, this._iat, 0, 0, this._diversifier, this._random, this._stk); this.write(Buffer.concat([Buffer.from([smp_1.SMP.PAIRING_RANDOM]), this._r])); } else { this.write(Buffer.from([smp_1.SMP.PAIRING_FAILED, smp_1.SMP.PAIRING_CONFIRM])); this.emit('fail'); } } handlePairingFailed(data) { this.emit('fail'); } write(data) { this._aclStream.write(smp_1.SMP.CID, data); } } exports.Smp = Smp;