ProvisioningCipher.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. (function() {
  2. 'use strict';
  3. function ProvisioningCipher() {}
  4. ProvisioningCipher.prototype = {
  5. decrypt: function(provisionEnvelope) {
  6. var masterEphemeral = provisionEnvelope.publicKey.toArrayBuffer();
  7. var message = provisionEnvelope.body.toArrayBuffer();
  8. if (new Uint8Array(message)[0] != 1) {
  9. throw new Error("Bad version number on ProvisioningMessage");
  10. }
  11. var iv = message.slice(1, 16 + 1);
  12. var mac = message.slice(message.byteLength - 32, message.byteLength);
  13. var ivAndCiphertext = message.slice(0, message.byteLength - 32);
  14. var ciphertext = message.slice(16 + 1, message.byteLength - 32);
  15. return libsignal.Curve.async.calculateAgreement(
  16. masterEphemeral, this.keyPair.privKey
  17. ).then(function(ecRes) {
  18. return libsignal.HKDF.deriveSecrets(
  19. ecRes, new ArrayBuffer(32), "TextSecure Provisioning Message"
  20. );
  21. }).then(function(keys) {
  22. return libsignal.crypto.verifyMAC(ivAndCiphertext, keys[1], mac, 32).then(function() {
  23. return libsignal.crypto.decrypt(keys[0], ciphertext, iv);
  24. });
  25. }).then(function(plaintext) {
  26. var provisionMessage = textsecure.protobuf.ProvisionMessage.decode(plaintext);
  27. var privKey = provisionMessage.identityKeyPrivate.toArrayBuffer();
  28. return libsignal.Curve.async.createKeyPair(privKey).then(function(keyPair) {
  29. return {
  30. identityKeyPair : keyPair,
  31. number : provisionMessage.number,
  32. provisioningCode : provisionMessage.provisioningCode,
  33. userAgent : provisionMessage.userAgent
  34. };
  35. });
  36. });
  37. },
  38. getPublicKey: function() {
  39. return Promise.resolve().then(function() {
  40. if (!this.keyPair) {
  41. return libsignal.Curve.async.generateKeyPair().then(function(keyPair) {
  42. this.keyPair = keyPair;
  43. }.bind(this));
  44. }
  45. }.bind(this)).then(function() {
  46. return this.keyPair.pubKey;
  47. }.bind(this));
  48. }
  49. };
  50. libsignal.ProvisioningCipher = function() {
  51. var cipher = new ProvisioningCipher();
  52. this.decrypt = cipher.decrypt.bind(cipher);
  53. this.getPublicKey = cipher.getPublicKey.bind(cipher);
  54. };
  55. })();