xiot-core-xcp-ts
Version:
139 lines (138 loc) • 6.97 kB
JavaScript
"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;