UNPKG

xiot-core-xcp-ts

Version:
139 lines (138 loc) 6.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.XcpClientVerifierImpl = void 0; const XcpSessionKey_1 = require("../common/XcpSessionKey"); const XcpFrameCodecType_1 = require("../common/XcpFrameCodecType"); const XcpAuthenticationType_1 = require("../common/XcpAuthenticationType"); const KeyPair_1 = require("../KeyPair"); const XcpKeyCreator_1 = require("../key/XcpKeyCreator"); const XcpKeyType_1 = require("../key/XcpKeyType"); const Uint8ArrayUtils_1 = require("../utils/Uint8ArrayUtils"); const chacha20poly1305_1 = require("@stablelib/chacha20poly1305"); const Initialize_1 = require("../../stanza/typedef/iq/device/verify/Initialize"); const VerifyStart_1 = require("../../stanza/typedef/iq/device/verify/VerifyStart"); const VerifyFinish_1 = require("../../stanza/typedef/iq/device/verify/VerifyFinish"); const mipher_ts_1 = require("mipher-ts"); class XcpClientVerifierImpl { constructor(client, version, cipher, codec) { this.client = client; this.version = version; this.cipher = cipher; this.codec = codec; this.sharedKey = null; this.verifyKey = null; this.sessionInfo = null; } start() { return this.initialization() .then(x => this.verifyStart(x)) .then(n => this.verifyFinish(n)); } initialization() { const auth = XcpAuthenticationType_1.XcpAuthenticationTypeToString(this.cipher.getAuthenticationType()); const query = new Initialize_1.QueryInitialize(this.client.getNextStanzaId(), this.version, auth); return this.client.sendQuery(query).then(() => this.generateKeyPair()); } generateKeyPair() { const random = new mipher_ts_1.Random(); const c = new mipher_ts_1.Curve25519(); const seed = random.get(32); const k = c.generateKeys(seed); return new KeyPair_1.KeyPair(k.pk, k.sk); } verifyStart(keyPair) { const publicKey = Uint8ArrayUtils_1.Bin2Base64(keyPair.pk); console.log('verifyStart publicKey: ' + publicKey); const query = new VerifyStart_1.QueryVerifyStart(this.client.getNextStanzaId(), publicKey); return this.client.sendQuery(query).then(x => this.parseResultVerifyStart(keyPair, x)); } parseResultVerifyStart(keyPair, x) { if (!(x instanceof VerifyStart_1.ResultVerifyStart)) { throw new Error('invalid result'); } const serverPublicKey = Uint8ArrayUtils_1.Base642Bin(x.publicKey); const serverEncryptedSignature = Uint8ArrayUtils_1.Base642Bin(x.signature); console.log('serverPublicKey: ', serverPublicKey); console.log('serverEncryptedSignature: ', serverEncryptedSignature); const c = new mipher_ts_1.Curve25519(); this.sharedKey = c.scalarMult(keyPair.sk, serverPublicKey); console.log('SharedKey: ', Uint8ArrayUtils_1.Bin2Base64(this.sharedKey)); this.verifyKey = XcpKeyCreator_1.XcpKeyCreator.create(this.sharedKey, XcpKeyType_1.XcpKeyType.SESSION_VERIFY_ENCRYPT_KEY); if (this.verifyKey != null) { console.log('VerifyKey: ', Uint8ArrayUtils_1.Bin2Base64(this.verifyKey)); } this.sessionInfo = Uint8ArrayUtils_1.BytesJoin(keyPair.pk, serverPublicKey); console.log('SessionInfo: ', Uint8ArrayUtils_1.Bin2Base64(this.sessionInfo)); return serverEncryptedSignature; } verifyFinish(serverEncryptedSignature) { if (this.verifyKey == null || this.sessionInfo == null) { throw new Error('invalid result'); } const cc = new chacha20poly1305_1.ChaCha20Poly1305(this.verifyKey); const serverSignature = cc.open(Uint8ArrayUtils_1.StringToUint8Array('SV-Msg02'), serverEncryptedSignature); if (serverSignature == null) { console.log('decode serverSignature failed, serverSignature is null'); throw new Error('decode serverSignature failed, serverSignature is null'); } return this.verify(this.sessionInfo, serverSignature) .then(x => this.sign(this.sessionInfo)) .then(x => this.parseQueryVerifyFinish(x, cc)) .then(x => this.client.sendQuery(x)) .then(x => this.parseResultVerifyFinish(x)); } sign(sessionInfo = null) { if (sessionInfo == null) { return Promise.reject('sessionInfo is null'); } return this.cipher.sign(sessionInfo); } verify(sessionInfo, serverSignature) { return new Promise((resolve, reject) => { this.cipher.verify(sessionInfo, serverSignature) .then(x => { if (x) { resolve(x); } else { reject('server signature verify failed'); } }).catch(err => { console.error(err); reject(err); }); }); } parseQueryVerifyFinish(signature, cc) { const encryptedSignature = Uint8ArrayUtils_1.Bin2Base64(cc.seal(Uint8ArrayUtils_1.StringToUint8Array('SV-Msg03'), signature)); console.log('device signature: ', Uint8ArrayUtils_1.Bin2Base64(signature)); const deviceId = Uint8ArrayUtils_1.Bin2Base64(cc.seal(Uint8ArrayUtils_1.StringToUint8Array('SV-Msg03'), Uint8ArrayUtils_1.StringToUint8Array(this.client.getDeviceId()))); const deviceType = Uint8ArrayUtils_1.Bin2Base64(cc.seal(Uint8ArrayUtils_1.StringToUint8Array('SV-Msg03'), Uint8ArrayUtils_1.StringToUint8Array(this.client.getDeviceType()))); const id = this.client.getNextStanzaId(); const frameCodecType = XcpFrameCodecType_1.XcpFrameCodecTypeToNumber(this.codec); const query = new VerifyFinish_1.QueryVerifyFinish(id, deviceId, deviceType, encryptedSignature, frameCodecType); return Promise.resolve(query); } parseResultVerifyFinish(x) { if (!(x instanceof VerifyFinish_1.ResultVerifyFinish)) { throw new Error('invalid result'); } if (this.sharedKey == null) { throw new Error('invalid result'); } const outKey = XcpKeyCreator_1.XcpKeyCreator.create(this.sharedKey, XcpKeyType_1.XcpKeyType.DEVICE_TO_SERVER_KEY); if (outKey == null) { throw new Error('invalid result'); } const inKey = XcpKeyCreator_1.XcpKeyCreator.create(this.sharedKey, XcpKeyType_1.XcpKeyType.SERVER_TO_DEVICE_KEY); if (inKey == null) { throw new Error('invalid result'); } // console.log('outKey: ', Convert.bin2base64(outKey)); // console.log('inKey: ', Convert.bin2base64(inKey)); console.log('outKey: ', Uint8ArrayUtils_1.Bin2Base64(outKey)); console.log('inKey: ', Uint8ArrayUtils_1.Bin2Base64(inKey)); return new XcpSessionKey_1.XcpSessionKey(this.codec, outKey, inKey); } } exports.XcpClientVerifierImpl = XcpClientVerifierImpl;