@freesignal/protocol 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesignal/protocol",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Signal Protocol implementation in javascript",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Christian Braghette",
package/test.js CHANGED
@@ -2,7 +2,6 @@
2
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
- var _a, _b;
6
5
  Object.defineProperty(exports, "__esModule", { value: true });
7
6
  const _1 = require(".");
8
7
  const crypto_1 = __importDefault(require("./crypto"));
@@ -12,20 +11,22 @@ const bob = (0, _1.createKeyExchange)(crypto_1.default.EdDSA.keyPair().secretKey
12
11
  const alice = (0, _1.createKeyExchange)(crypto_1.default.EdDSA.keyPair().secretKey, crypto_1.default.ECDH.keyPair().secretKey);
13
12
  const bobmessage = bob.generateData();
14
13
  const { session: alicesession, message: aliceack } = alice.digestData(bobmessage);
15
- const { session: bobsession, cleartext } = (_a = bob.digestMessage(aliceack)) !== null && _a !== void 0 ? _a : {};
16
- if (bobsession && cleartext) {
17
- console.log("Session established successfully between Alice and Bob.");
18
- const datagram = data_1.Datagram.create(bob.signatureKey, alice.signatureKey, data_1.Protocols.MESSAGE, (_b = bobsession.encrypt((0, utils_1.decodeUTF8)("Hi Alice!"))) === null || _b === void 0 ? void 0 : _b.encode());
19
- //console.log(datagram.payload);
20
- const msg = datagram.encode();
21
- console.log((0, utils_1.encodeUTF8)(alicesession.decrypt(data_1.Datagram.from(msg).payload)));
22
- if (alicesession.handshaked && bobsession.handshaked)
23
- console.log("Successfully handshaked");
14
+ bob.digestMessage(aliceack).then(({ session: bobsession, cleartext }) => {
15
+ var _a;
16
+ if (bobsession && cleartext) {
17
+ console.log("Session established successfully between Alice and Bob.");
18
+ const datagram = data_1.Datagram.create(bob.signatureKey, alice.signatureKey, data_1.Protocols.MESSAGE, (_a = bobsession.encrypt((0, utils_1.decodeUTF8)("Hi Alice!"))) === null || _a === void 0 ? void 0 : _a.encode());
19
+ //console.log(datagram.payload);
20
+ const msg = datagram.encode();
21
+ console.log((0, utils_1.encodeUTF8)(alicesession.decrypt(data_1.Datagram.from(msg).payload)));
22
+ if (alicesession.handshaked && bobsession.handshaked)
23
+ console.log("Successfully handshaked");
24
+ else
25
+ console.log("Error during handshake");
26
+ const longmsg = data_1.Datagram.create(alice.signatureKey, bob.signatureKey, data_1.Protocols.MESSAGE, alicesession.encrypt(new Uint8Array(1000000).fill(33).map(val => val + Math.floor(Math.random() * 93))));
27
+ console.log(longmsg.encode().length);
28
+ console.log(longmsg.encode(false).length);
29
+ }
24
30
  else
25
- console.log("Error during handshake");
26
- const longmsg = data_1.Datagram.create(alice.signatureKey, bob.signatureKey, data_1.Protocols.MESSAGE, alicesession.encrypt(new Uint8Array(1000000).fill(33).map(val => val + Math.floor(Math.random() * 93))));
27
- console.log(longmsg.encode().length);
28
- console.log(longmsg.encode(false).length);
29
- }
30
- else
31
- console.log("Error");
31
+ console.log("Error");
32
+ });
package/types.d.ts CHANGED
@@ -27,11 +27,11 @@ export declare namespace Encodable {
27
27
  }
28
28
  type LocalStorageIterator<T> = Iterable<T>;
29
29
  export interface LocalStorage<K, T> {
30
- set(key: K, value: T): this;
31
- get(key: K): T | undefined;
32
- has(key: K): boolean;
33
- delete(key: K): boolean;
34
- entries(): LocalStorageIterator<[K, T]>;
30
+ set(key: K, value: T): Promise<this>;
31
+ get(key: K): Promise<T | undefined>;
32
+ has(key: K): Promise<boolean>;
33
+ delete(key: K): Promise<boolean>;
34
+ entries(): Promise<LocalStorageIterator<[K, T]>>;
35
35
  }
36
36
  export interface KeyExchangeData {
37
37
  readonly version: number;
package/x3dh.d.ts CHANGED
@@ -37,8 +37,8 @@ export declare class KeyExchange {
37
37
  session: KeySession;
38
38
  message: KeyExchangeSynMessage;
39
39
  };
40
- digestMessage(message: KeyExchangeSynMessage): {
40
+ digestMessage(message: KeyExchangeSynMessage): Promise<{
41
41
  session: KeySession;
42
42
  cleartext: Uint8Array;
43
- };
43
+ }>;
44
44
  }
package/x3dh.js CHANGED
@@ -17,6 +17,15 @@
17
17
  * You should have received a copy of the GNU General Public License
18
18
  * along with this program. If not, see <https://www.gnu.org/licenses/>
19
19
  */
20
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
22
+ return new (P || (P = Promise))(function (resolve, reject) {
23
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
24
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
25
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
26
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
27
+ });
28
+ };
20
29
  var __importDefault = (this && this.__importDefault) || function (mod) {
21
30
  return (mod && mod.__esModule) ? mod : { "default": mod };
22
31
  };
@@ -29,7 +38,7 @@ class KeyExchange {
29
38
  constructor(signSecretKey, boxSecretKey, bundleStore) {
30
39
  this._signatureKey = crypto_1.default.EdDSA.keyPair(signSecretKey);
31
40
  this._identityKey = crypto_1.default.ECDH.keyPair(boxSecretKey);
32
- this.bundleStore = bundleStore !== null && bundleStore !== void 0 ? bundleStore : new Map();
41
+ this.bundleStore = bundleStore !== null && bundleStore !== void 0 ? bundleStore : new AsyncMap();
33
42
  }
34
43
  get signatureKey() { return this._signatureKey.publicKey; }
35
44
  get identityKey() { return this._identityKey.publicKey; }
@@ -72,7 +81,7 @@ class KeyExchange {
72
81
  digestData(message) {
73
82
  const ephemeralKey = crypto_1.default.ECDH.keyPair();
74
83
  const signedPreKey = (0, utils_1.decodeBase64)(message.signedPreKey);
75
- if (!crypto_1.default.EdDSA.verify(signedPreKey, (0, utils_1.decodeBase64)(message.signature), (0, utils_1.decodeBase64)(message.publicKey)))
84
+ if (!crypto_1.default.EdDSA.verify(crypto_1.default.hash(signedPreKey), (0, utils_1.decodeBase64)(message.signature), (0, utils_1.decodeBase64)(message.publicKey)))
76
85
  throw new Error("Signature verification failed");
77
86
  const identityKey = (0, utils_1.decodeBase64)(message.identityKey);
78
87
  const onetimePreKey = message.onetimePreKey ? (0, utils_1.decodeBase64)(message.onetimePreKey) : undefined;
@@ -102,31 +111,64 @@ class KeyExchange {
102
111
  };
103
112
  }
104
113
  digestMessage(message) {
105
- const signedPreKey = this.bundleStore.get(message.signedPreKeyHash);
106
- const hash = message.signedPreKeyHash.concat(message.onetimePreKeyHash);
107
- const onetimePreKey = this.bundleStore.get(hash);
108
- if (!signedPreKey || !onetimePreKey || !message.identityKey || !message.ephemeralKey)
109
- throw new Error("ACK message malformed");
110
- if (!this.bundleStore.delete(hash))
111
- throw new Error("Bundle store deleting error");
112
- const identityKey = (0, utils_1.decodeBase64)(message.identityKey);
113
- const ephemeralKey = (0, utils_1.decodeBase64)(message.ephemeralKey);
114
- const rootKey = crypto_1.default.hkdf(new Uint8Array([
115
- ...crypto_1.default.scalarMult(signedPreKey.secretKey, identityKey),
116
- ...crypto_1.default.scalarMult(this._identityKey.secretKey, ephemeralKey),
117
- ...crypto_1.default.scalarMult(signedPreKey.secretKey, ephemeralKey),
118
- ...onetimePreKey ? crypto_1.default.scalarMult(onetimePreKey.secretKey, ephemeralKey) : new Uint8Array()
119
- ]), new Uint8Array(double_ratchet_1.KeySession.rootKeyLength).fill(0), KeyExchange.hkdfInfo, double_ratchet_1.KeySession.rootKeyLength);
120
- const session = new double_ratchet_1.KeySession({ secretKey: this._identityKey.secretKey, rootKey });
121
- const cleartext = session.decrypt((0, utils_1.decodeBase64)(message.associatedData));
122
- if (!cleartext)
123
- throw new Error("Error decrypting ACK message");
124
- if (!(0, utils_1.verifyUint8Array)(cleartext, (0, utils_1.concatUint8Array)(crypto_1.default.hash(identityKey), crypto_1.default.hash(this._identityKey.publicKey))))
125
- throw new Error("Error verifing Associated Data");
126
- return { session, cleartext };
114
+ return __awaiter(this, void 0, void 0, function* () {
115
+ const signedPreKey = yield this.bundleStore.get(message.signedPreKeyHash);
116
+ const hash = message.signedPreKeyHash.concat(message.onetimePreKeyHash);
117
+ const onetimePreKey = yield this.bundleStore.get(hash);
118
+ if (!signedPreKey || !onetimePreKey || !message.identityKey || !message.ephemeralKey)
119
+ throw new Error("ACK message malformed");
120
+ if (!this.bundleStore.delete(hash))
121
+ throw new Error("Bundle store deleting error");
122
+ const identityKey = (0, utils_1.decodeBase64)(message.identityKey);
123
+ const ephemeralKey = (0, utils_1.decodeBase64)(message.ephemeralKey);
124
+ const rootKey = crypto_1.default.hkdf(new Uint8Array([
125
+ ...crypto_1.default.scalarMult(signedPreKey.secretKey, identityKey),
126
+ ...crypto_1.default.scalarMult(this._identityKey.secretKey, ephemeralKey),
127
+ ...crypto_1.default.scalarMult(signedPreKey.secretKey, ephemeralKey),
128
+ ...onetimePreKey ? crypto_1.default.scalarMult(onetimePreKey.secretKey, ephemeralKey) : new Uint8Array()
129
+ ]), new Uint8Array(double_ratchet_1.KeySession.rootKeyLength).fill(0), KeyExchange.hkdfInfo, double_ratchet_1.KeySession.rootKeyLength);
130
+ const session = new double_ratchet_1.KeySession({ secretKey: this._identityKey.secretKey, rootKey });
131
+ const cleartext = session.decrypt((0, utils_1.decodeBase64)(message.associatedData));
132
+ if (!cleartext)
133
+ throw new Error("Error decrypting ACK message");
134
+ if (!(0, utils_1.verifyUint8Array)(cleartext, (0, utils_1.concatUint8Array)(crypto_1.default.hash(identityKey), crypto_1.default.hash(this._identityKey.publicKey))))
135
+ throw new Error("Error verifing Associated Data");
136
+ return { session, cleartext };
137
+ });
127
138
  }
128
139
  }
129
140
  exports.KeyExchange = KeyExchange;
130
141
  KeyExchange.version = 1;
131
142
  KeyExchange.hkdfInfo = (0, utils_1.decodeUTF8)("freesignal/x3dh/" + KeyExchange.version);
132
143
  KeyExchange.maxOPK = 10;
144
+ class AsyncMap {
145
+ constructor() {
146
+ this.map = new Map();
147
+ }
148
+ set(key, value) {
149
+ return __awaiter(this, void 0, void 0, function* () {
150
+ this.map.set(key, value);
151
+ return this;
152
+ });
153
+ }
154
+ get(key) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ return this.map.get(key);
157
+ });
158
+ }
159
+ has(key) {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ return this.map.has(key);
162
+ });
163
+ }
164
+ delete(key) {
165
+ return __awaiter(this, void 0, void 0, function* () {
166
+ return this.map.delete(key);
167
+ });
168
+ }
169
+ entries() {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ return this.map.entries();
172
+ });
173
+ }
174
+ }