(function() { 'use strict'; function ProvisioningCipher() {} ProvisioningCipher.prototype = { decrypt: function(provisionEnvelope) { var masterEphemeral = provisionEnvelope.publicKey.toArrayBuffer(); var message = provisionEnvelope.body.toArrayBuffer(); if (new Uint8Array(message)[0] != 1) { throw new Error('Bad version number on ProvisioningMessage'); } var iv = message.slice(1, 16 + 1); var mac = message.slice(message.byteLength - 32, message.byteLength); var ivAndCiphertext = message.slice(0, message.byteLength - 32); var ciphertext = message.slice(16 + 1, message.byteLength - 32); return libsignal.Curve.async .calculateAgreement(masterEphemeral, this.keyPair.privKey) .then(function(ecRes) { return libsignal.HKDF.deriveSecrets( ecRes, new ArrayBuffer(32), 'TextSecure Provisioning Message' ); }) .then(function(keys) { return libsignal.crypto .verifyMAC(ivAndCiphertext, keys[1], mac, 32) .then(function() { return libsignal.crypto.decrypt(keys[0], ciphertext, iv); }); }) .then(function(plaintext) { var provisionMessage = textsecure.protobuf.ProvisionMessage.decode( plaintext ); var privKey = provisionMessage.identityKeyPrivate.toArrayBuffer(); return libsignal.Curve.async .createKeyPair(privKey) .then(function(keyPair) { var ret = { identityKeyPair: keyPair, number: provisionMessage.number, provisioningCode: provisionMessage.provisioningCode, userAgent: provisionMessage.userAgent, readReceipts: provisionMessage.readReceipts, }; if (provisionMessage.profileKey) { ret.profileKey = provisionMessage.profileKey.toArrayBuffer(); } return ret; }); }); }, getPublicKey: function() { return Promise.resolve() .then( function() { if (!this.keyPair) { return libsignal.Curve.async.generateKeyPair().then( function(keyPair) { this.keyPair = keyPair; }.bind(this) ); } }.bind(this) ) .then( function() { return this.keyPair.pubKey; }.bind(this) ); }, }; libsignal.ProvisioningCipher = function() { var cipher = new ProvisioningCipher(); this.decrypt = cipher.decrypt.bind(cipher); this.getPublicKey = cipher.getPublicKey.bind(cipher); }; })();