signal-desktop/libtextsecure/ProvisioningCipher.js

79 lines
2.6 KiB
JavaScript
Raw Normal View History

2018-07-21 21:51:20 +00:00
/* global libsignal, textsecure */
/* eslint-disable more/no-then */
2018-07-21 21:51:20 +00:00
// eslint-disable-next-line func-names
(function() {
2018-05-02 16:51:22 +00:00
function ProvisioningCipher() {}
2018-05-02 16:51:22 +00:00
ProvisioningCipher.prototype = {
2018-07-21 21:51:20 +00:00
decrypt(provisionEnvelope) {
const masterEphemeral = provisionEnvelope.publicKey.toArrayBuffer();
const message = provisionEnvelope.body.toArrayBuffer();
if (new Uint8Array(message)[0] !== 1) {
2018-05-02 16:51:22 +00:00
throw new Error('Bad version number on ProvisioningMessage');
}
2018-07-21 21:51:20 +00:00
const iv = message.slice(1, 16 + 1);
const mac = message.slice(message.byteLength - 32, message.byteLength);
const ivAndCiphertext = message.slice(0, message.byteLength - 32);
const ciphertext = message.slice(16 + 1, message.byteLength - 32);
2018-05-02 16:51:22 +00:00
return libsignal.Curve.async
.calculateAgreement(masterEphemeral, this.keyPair.privKey)
2018-07-21 21:51:20 +00:00
.then(ecRes =>
libsignal.HKDF.deriveSecrets(
2018-05-02 16:51:22 +00:00
ecRes,
new ArrayBuffer(32),
'TextSecure Provisioning Message'
2018-07-21 21:51:20 +00:00
)
)
.then(keys =>
libsignal.crypto
2018-05-02 16:51:22 +00:00
.verifyMAC(ivAndCiphertext, keys[1], mac, 32)
2018-07-21 21:51:20 +00:00
.then(() => libsignal.crypto.decrypt(keys[0], ciphertext, iv))
)
.then(plaintext => {
const provisionMessage = textsecure.protobuf.ProvisionMessage.decode(
2018-05-02 16:51:22 +00:00
plaintext
);
2018-07-21 21:51:20 +00:00
const privKey = provisionMessage.identityKeyPrivate.toArrayBuffer();
2018-07-21 21:51:20 +00:00
return libsignal.Curve.async.createKeyPair(privKey).then(keyPair => {
const 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;
});
});
},
2018-07-21 21:51:20 +00:00
getPublicKey() {
2018-05-02 16:51:22 +00:00
return Promise.resolve()
2018-07-21 21:51:20 +00:00
.then(() => {
if (!this.keyPair) {
return libsignal.Curve.async.generateKeyPair().then(keyPair => {
this.keyPair = keyPair;
});
}
return null;
})
.then(() => this.keyPair.pubKey);
2018-05-02 16:51:22 +00:00
},
};
2018-07-21 21:51:20 +00:00
libsignal.ProvisioningCipher = function ProvisioningCipherWrapper() {
const cipher = new ProvisioningCipher();
2018-05-02 16:51:22 +00:00
this.decrypt = cipher.decrypt.bind(cipher);
this.getPublicKey = cipher.getPublicKey.bind(cipher);
2018-05-02 16:51:22 +00:00
};
})();