@freesignal/protocol 0.6.2 → 0.7.0

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.
@@ -20,9 +20,11 @@ import { IdentityKey, UserId } from "./types";
20
20
  export interface ExportedKeySession {
21
21
  identityKey: string;
22
22
  secretKey: string;
23
- rootKey?: string;
23
+ rootKey: string;
24
24
  sendingChain?: ExportedKeyChain;
25
25
  receivingChain?: ExportedKeyChain;
26
+ headerKey?: string;
27
+ headerKeys: [string, Uint8Array][];
26
28
  previousKeys: [string, Uint8Array][];
27
29
  }
28
30
  export interface EncryptionKeys {
@@ -44,19 +46,24 @@ export declare class KeySession {
44
46
  static readonly maxCount = 65536;
45
47
  readonly identityKey: IdentityKey;
46
48
  private keyPair;
47
- private rootKey?;
49
+ private rootKey;
48
50
  private sendingChain?;
49
51
  private receivingChain?;
52
+ private readonly headerKeys;
53
+ private headerKey?;
50
54
  private nextHeaderKey?;
51
55
  private previousKeys;
52
- constructor({ identityKey, secretKey, remoteKey, rootKey }: {
56
+ constructor({ identityKey, secretKey, remoteKey, rootKey, headerKey, nextHeaderKey }: {
53
57
  identityKey: IdentityKey;
54
58
  secretKey?: Uint8Array;
55
59
  remoteKey?: Uint8Array;
56
- rootKey?: Uint8Array;
60
+ rootKey: Uint8Array;
61
+ headerKey?: Uint8Array;
62
+ nextHeaderKey?: Uint8Array;
57
63
  });
58
64
  get userId(): UserId;
59
65
  private getChain;
66
+ getHeaderKey(hash?: string): Uint8Array | undefined;
60
67
  getSendingKey(): PrivateEncryptionKeys | undefined;
61
68
  getReceivingKey(encryptionKeys: EncryptionKeys): Uint8Array | undefined;
62
69
  /**
@@ -83,6 +90,8 @@ interface ExportedKeyChain {
83
90
  publicKey: string;
84
91
  remoteKey: string;
85
92
  chainKey: string;
93
+ headerKey?: string;
94
+ nextHeaderKey: string;
86
95
  count: number;
87
96
  previousCount: number;
88
97
  }
@@ -30,41 +30,40 @@ const types_1 = require("./types");
30
30
  * Used for forward-secure encryption and decryption of messages.
31
31
  */
32
32
  class KeySession {
33
- //headerKey?: Uint8Array, nextHeaderKey?: Uint8Array,
34
- constructor({ identityKey, secretKey, remoteKey, rootKey }) {
33
+ constructor({ identityKey, secretKey, remoteKey, rootKey, headerKey, nextHeaderKey }) {
34
+ this.headerKeys = new Map();
35
35
  this.previousKeys = new KeyMap();
36
36
  this.identityKey = identityKey;
37
37
  this.keyPair = crypto_1.default.ECDH.keyPair(secretKey);
38
- if (rootKey)
39
- this.rootKey = rootKey;
40
- //if (opts.nextHeaderKey)
41
- // this.nextHeaderKey = opts.nextHeaderKey;
38
+ this.rootKey = rootKey;
39
+ if (headerKey)
40
+ this.headerKey = headerKey;
41
+ if (nextHeaderKey) {
42
+ this.nextHeaderKey = nextHeaderKey;
43
+ this.headerKeys.set((0, utils_1.decodeBase64)(crypto_1.default.hash(nextHeaderKey)), nextHeaderKey);
44
+ }
42
45
  if (remoteKey) {
43
- this.sendingChain = this.getChain(remoteKey); //, opts.headerKey);
46
+ this.sendingChain = this.getChain(remoteKey, this.headerKey);
47
+ this.headerKey = undefined;
44
48
  }
45
49
  }
46
50
  get userId() {
47
51
  return this.identityKey.userId;
48
52
  }
49
- //headerKey?: Uint8Array,
50
- getChain(remoteKey, previousCount) {
53
+ getChain(remoteKey, headerKey, previousCount) {
51
54
  const sharedKey = crypto_1.default.ECDH.scalarMult(this.keyPair.secretKey, remoteKey);
52
55
  if (!this.rootKey)
53
56
  this.rootKey = crypto_1.default.hash(sharedKey);
54
57
  const hashkey = crypto_1.default.hkdf(sharedKey, this.rootKey, KeySession.info, KeySession.keyLength * 3);
55
58
  this.rootKey = hashkey.subarray(0, KeySession.keyLength);
56
- //hashkey.subarray(KeySession.keyLength * 2), headerKey,
57
- return new KeyChain(this.publicKey, remoteKey, hashkey.subarray(KeySession.keyLength, KeySession.keyLength * 2), previousCount);
59
+ return new KeyChain(this.publicKey, remoteKey, hashkey.subarray(KeySession.keyLength, KeySession.keyLength * 2), hashkey.subarray(KeySession.keyLength * 2), headerKey, previousCount);
60
+ }
61
+ getHeaderKey(hash) {
62
+ var _a, _b;
63
+ if (!hash)
64
+ return (_a = this.headerKey) !== null && _a !== void 0 ? _a : (_b = this.sendingChain) === null || _b === void 0 ? void 0 : _b.headerKey;
65
+ return this.headerKeys.get(hash);
58
66
  }
59
- /*public getHeaderKeys(): {
60
- readonly sending?: Uint8Array,
61
- readonly receiving?: Uint8Array
62
- } {
63
- return {
64
- sending: this.sendingChain?.headerKey,
65
- receiving: (this.receivingChain?.headerKey ?? this.receivingChain?.nextHeaderKey) ?? this.nextHeaderKey
66
- }
67
- }*/
68
67
  getSendingKey() {
69
68
  if (!this.sendingChain)
70
69
  return;
@@ -78,19 +77,21 @@ class KeySession {
78
77
  };
79
78
  }
80
79
  getReceivingKey(encryptionKeys) {
81
- var _a, _b, _c, _d;
80
+ var _a, _b, _c, _d, _e, _f, _g, _h;
82
81
  if (!this.previousKeys.has((0, utils_1.decodeBase64)(encryptionKeys.publicKey) + encryptionKeys.count.toString())) {
83
82
  if (!(0, utils_1.compareBytes)(encryptionKeys.publicKey, (_b = (_a = this.receivingChain) === null || _a === void 0 ? void 0 : _a.remoteKey) !== null && _b !== void 0 ? _b : new Uint8Array())) {
84
83
  while (this.receivingChain && this.receivingChain.count < encryptionKeys.previous) {
85
84
  const key = this.receivingChain.getKey();
86
85
  this.previousKeys.set((0, utils_1.decodeBase64)(this.receivingChain.remoteKey) + this.receivingChain.count.toString(), key);
87
86
  }
88
- //this.nextHeaderKey ?? this.receivingChain?.nextHeaderKey
89
- this.receivingChain = this.getChain(encryptionKeys.publicKey, (_c = this.receivingChain) === null || _c === void 0 ? void 0 : _c.count);
90
- this.nextHeaderKey = undefined;
87
+ this.receivingChain = this.getChain(encryptionKeys.publicKey, (_c = this.nextHeaderKey) !== null && _c !== void 0 ? _c : (_d = this.receivingChain) === null || _d === void 0 ? void 0 : _d.nextHeaderKey, (_e = this.receivingChain) === null || _e === void 0 ? void 0 : _e.count);
88
+ this.headerKeys.set((0, utils_1.decodeBase64)(crypto_1.default.hash(this.receivingChain.nextHeaderKey)), this.receivingChain.nextHeaderKey);
89
+ if (this.nextHeaderKey)
90
+ this.nextHeaderKey = undefined;
91
91
  this.keyPair = crypto_1.default.ECDH.keyPair();
92
- //this.sendingChain?.nextHeaderKey,
93
- this.sendingChain = this.getChain(encryptionKeys.publicKey, (_d = this.sendingChain) === null || _d === void 0 ? void 0 : _d.count);
92
+ this.sendingChain = this.getChain(encryptionKeys.publicKey, (_f = this.headerKey) !== null && _f !== void 0 ? _f : (_g = this.sendingChain) === null || _g === void 0 ? void 0 : _g.nextHeaderKey, (_h = this.sendingChain) === null || _h === void 0 ? void 0 : _h.count);
93
+ if (this.headerKey)
94
+ this.headerKey = undefined;
94
95
  }
95
96
  if (!this.receivingChain)
96
97
  throw new Error("Error initializing receivingChain");
@@ -117,9 +118,11 @@ class KeySession {
117
118
  return {
118
119
  identityKey: this.identityKey.toString(),
119
120
  secretKey: (0, utils_1.decodeBase64)(this.keyPair.secretKey),
120
- rootKey: this.rootKey ? (0, utils_1.decodeBase64)(this.rootKey) : undefined,
121
+ rootKey: (0, utils_1.decodeBase64)(this.rootKey),
121
122
  sendingChain: (_a = this.sendingChain) === null || _a === void 0 ? void 0 : _a.toJSON(),
122
123
  receivingChain: (_b = this.receivingChain) === null || _b === void 0 ? void 0 : _b.toJSON(),
124
+ headerKey: this.headerKey ? (0, utils_1.decodeBase64)(this.headerKey) : undefined,
125
+ headerKeys: Array.from(this.headerKeys.entries()),
123
126
  previousKeys: Array.from(this.previousKeys.entries())
124
127
  };
125
128
  }
@@ -130,7 +133,7 @@ class KeySession {
130
133
  * @returns session with the state parsed.
131
134
  */
132
135
  static from(data) {
133
- const session = new KeySession({ identityKey: types_1.IdentityKey.from(data.identityKey), secretKey: (0, utils_1.encodeBase64)(data.secretKey), rootKey: data.rootKey ? (0, utils_1.encodeBase64)(data.rootKey) : undefined });
136
+ const session = new KeySession({ identityKey: types_1.IdentityKey.from(data.identityKey), secretKey: (0, utils_1.encodeBase64)(data.secretKey), rootKey: (0, utils_1.encodeBase64)(data.rootKey) });
134
137
  session.sendingChain = data.sendingChain ? KeyChain.from(data.sendingChain) : undefined;
135
138
  session.receivingChain = data.receivingChain ? KeyChain.from(data.receivingChain) : undefined;
136
139
  session.previousKeys = new KeyMap(data.previousKeys);
@@ -143,11 +146,12 @@ KeySession.version = 1;
143
146
  KeySession.info = "/freesignal/double-ratchet/v0." + KeySession.version;
144
147
  KeySession.maxCount = 65536;
145
148
  class KeyChain {
146
- //public readonly nextHeaderKey: Uint8Array, public readonly headerKey?: Uint8Array,
147
- constructor(publicKey, remoteKey, chainKey, previousCount = 0) {
149
+ constructor(publicKey, remoteKey, chainKey, nextHeaderKey, headerKey, previousCount = 0) {
148
150
  this.publicKey = publicKey;
149
151
  this.remoteKey = remoteKey;
150
152
  this.chainKey = chainKey;
153
+ this.nextHeaderKey = nextHeaderKey;
154
+ this.headerKey = headerKey;
151
155
  this.previousCount = previousCount;
152
156
  this._count = 0;
153
157
  }
@@ -168,16 +172,16 @@ class KeyChain {
168
172
  return {
169
173
  publicKey: (0, utils_1.decodeBase64)(this.publicKey),
170
174
  remoteKey: (0, utils_1.decodeBase64)(this.remoteKey),
175
+ headerKey: this.headerKey ? (0, utils_1.decodeBase64)(this.headerKey) : undefined,
176
+ nextHeaderKey: (0, utils_1.decodeBase64)(this.nextHeaderKey),
171
177
  chainKey: (0, utils_1.decodeBase64)(this.chainKey),
172
- //nextHeaderKey: decodeBase64(this.nextHeaderKey),
173
- //headerKey: this.headerKey ? decodeBase64(this.headerKey) : undefined,
174
178
  count: this.count,
175
179
  previousCount: this.previousCount
176
180
  };
177
181
  }
178
182
  static from(obj) {
179
- //encodeBase64(obj.nextHeaderKey), obj.headerKey ? encodeBase64(obj.headerKey) : undefined,
180
- const chain = new KeyChain((0, utils_1.encodeBase64)(obj.publicKey), (0, utils_1.encodeBase64)(obj.remoteKey), (0, utils_1.encodeBase64)(obj.chainKey), obj.previousCount);
183
+ //
184
+ const chain = new KeyChain((0, utils_1.encodeBase64)(obj.publicKey), (0, utils_1.encodeBase64)(obj.remoteKey), (0, utils_1.encodeBase64)(obj.chainKey), (0, utils_1.encodeBase64)(obj.nextHeaderKey), obj.headerKey ? (0, utils_1.encodeBase64)(obj.headerKey) : undefined, obj.previousCount);
181
185
  chain._count = obj.count;
182
186
  return chain;
183
187
  }
package/dist/index.d.ts CHANGED
@@ -18,23 +18,8 @@
18
18
  */
19
19
  import { LocalStorage, Crypto, Database, KeyExchangeDataBundle } from "@freesignal/interfaces";
20
20
  import { ExportedKeySession } from "./double-ratchet";
21
- import { IdentityKey, PrivateIdentityKey } from "./types";
21
+ import { PrivateIdentityKey } from "./types";
22
22
  import { BootstrapRequest, FreeSignalNode } from "./node";
23
- /**
24
- * Creates a new Double Ratchet session for secure message exchange.
25
- *
26
- * @param opts - Optional parameters for session initialization.
27
- * @param opts.secretKey - The local party's secret key as a Uint8Array.
28
- * @param opts.remoteKey - The remote party's public key as a Uint8Array.
29
- * @param opts.rootKey - An optional root key to initialize the session.
30
- * @returns A new instance of {@link KeySession}.
31
- */
32
- /**
33
- * Creates a new X3DH (Extended Triple Diffie-Hellman) key exchange session.
34
- *
35
- * @param storage - Local storage for keys.
36
- * @returns A new instance of {@link KeyExchange}.
37
- */
38
23
  /**
39
24
  * Generates identity key
40
25
  *
@@ -46,7 +31,6 @@ export declare function createIdentity(seed?: Uint8Array): PrivateIdentityKey;
46
31
  export declare function createNode(storage: Database<{
47
32
  sessions: LocalStorage<string, ExportedKeySession>;
48
33
  keyExchange: LocalStorage<string, Crypto.KeyPair>;
49
- users: LocalStorage<string, IdentityKey>;
50
34
  bundles: LocalStorage<string, KeyExchangeDataBundle>;
51
35
  bootstraps: LocalStorage<string, BootstrapRequest>;
52
36
  }>, privateIdentityKey?: PrivateIdentityKey): FreeSignalNode;
package/dist/index.js CHANGED
@@ -40,27 +40,6 @@ exports.createNode = createNode;
40
40
  const crypto_1 = __importDefault(require("@freesignal/crypto"));
41
41
  const types_1 = require("./types");
42
42
  const node_1 = require("./node");
43
- /**
44
- * Creates a new Double Ratchet session for secure message exchange.
45
- *
46
- * @param opts - Optional parameters for session initialization.
47
- * @param opts.secretKey - The local party's secret key as a Uint8Array.
48
- * @param opts.remoteKey - The remote party's public key as a Uint8Array.
49
- * @param opts.rootKey - An optional root key to initialize the session.
50
- * @returns A new instance of {@link KeySession}.
51
- */
52
- /*export function createKeySession(storage: LocalStorage<string, ExportedKeySession>, opts?: { secretKey?: Uint8Array, remoteKey?: Uint8Array, rootKey?: Uint8Array }): KeySession {
53
- return new KeySession(storage, opts);
54
- }*/
55
- /**
56
- * Creates a new X3DH (Extended Triple Diffie-Hellman) key exchange session.
57
- *
58
- * @param storage - Local storage for keys.
59
- * @returns A new instance of {@link KeyExchange}.
60
- */
61
- /*export function createKeyExchange(storage: { keys: LocalStorage<string, Crypto.KeyPair>, sessions: LocalStorage<string, ExportedKeySession> }, privateIdentityKey?: PrivateIdentityKey): KeyExchange {
62
- return new KeyExchange(storage, privateIdentityKey);
63
- }*/
64
43
  /**
65
44
  * Generates identity key
66
45
  *
package/dist/node.d.ts CHANGED
@@ -20,16 +20,27 @@ import { Database, LocalStorage, Crypto, KeyExchangeDataBundle, KeyExchangeData
20
20
  import { Datagram, DatagramHeader, IdentityKey, PrivateIdentityKey, Protocols, UserId } from "./types";
21
21
  import { KeyExchange } from "./x3dh";
22
22
  import { ExportedKeySession, KeySession } from "./double-ratchet";
23
- export declare class BootstrapRequest {
23
+ import EventEmitter, { EventCall } from "easyemitter.ts";
24
+ export declare class BootstrapRequest extends EventEmitter<'change', BootstrapRequest> {
24
25
  #private;
25
26
  readonly senderId: UserId | string;
26
- private readonly datagram;
27
- constructor(senderId: UserId | string, datagram: Datagram);
27
+ private readonly keyExchangeData;
28
+ constructor(senderId: UserId | string, keyExchangeData: KeyExchangeData);
29
+ onChange: EventCall<'change', BootstrapRequest>;
28
30
  get status(): "pending" | "accepted" | "denied";
29
- get(): Promise<Datagram | undefined>;
30
- accept(): Promise<Datagram | undefined>;
31
+ get data(): KeyExchangeData | undefined;
32
+ accept(): void;
31
33
  deny(): void;
32
34
  }
35
+ type NodeEventData = {
36
+ header: DatagramHeader;
37
+ payload?: Uint8Array;
38
+ datagram?: Datagram;
39
+ };
40
+ type MessageEventData = {
41
+ header: DatagramHeader;
42
+ payload: Uint8Array;
43
+ };
33
44
  export declare class FreeSignalNode {
34
45
  protected readonly privateIdentityKey: PrivateIdentityKey;
35
46
  protected readonly sessions: SessionMap;
@@ -37,36 +48,33 @@ export declare class FreeSignalNode {
37
48
  protected readonly keyExchange: KeyExchange;
38
49
  protected readonly discovers: Set<string>;
39
50
  protected readonly bootstraps: LocalStorage<string, BootstrapRequest>;
51
+ protected readonly emitter: EventEmitter<"message" | "send" | "handshaked" | "ping", NodeEventData>;
40
52
  constructor(storage: Database<{
41
53
  sessions: LocalStorage<string, ExportedKeySession>;
42
54
  keyExchange: LocalStorage<string, Crypto.KeyPair>;
43
55
  bundles: LocalStorage<string, KeyExchangeDataBundle>;
44
56
  bootstraps: LocalStorage<string, BootstrapRequest>;
45
57
  }>, privateIdentityKey?: PrivateIdentityKey);
58
+ onMessage: (data: MessageEventData) => void;
59
+ onSend: (data: Uint8Array) => void;
60
+ onHandshaked: (userId: UserId) => void;
61
+ waitHandshaked(userId: UserId | string, timeout?: number): Promise<void>;
46
62
  get identityKey(): IdentityKey;
47
63
  get userId(): UserId;
48
- onRequest: (request: BootstrapRequest) => void;
49
- getRequest(userId: string): Promise<Datagram | undefined>;
64
+ readonly requests: {
65
+ onRequest: (request: BootstrapRequest) => void;
66
+ getRequest: (userId: string) => Promise<BootstrapRequest | undefined>;
67
+ };
50
68
  protected encrypt(receiverId: string | UserId, protocol: Protocols, data: Uint8Array): Promise<Datagram>;
51
- packHandshake(data: KeyExchangeData): Promise<Datagram>;
52
- packHandshake(receiverId: string | UserId): Promise<Datagram>;
53
- packData<T>(receiverId: string | UserId, data: T): Promise<Datagram>;
54
- packRelay(receiverId: string | UserId, data: Datagram): Promise<Datagram>;
55
- packDiscover(receiverId: string | UserId, discoverId: string | UserId): Promise<Datagram>;
56
- packBootstrap(receiverId: string | UserId): Promise<Datagram>;
57
- packGetBootstrap(receiverId: string | UserId): Promise<Datagram>;
69
+ sendHandshake(data: KeyExchangeData): Promise<void>;
70
+ sendHandshake(receiverId: string | UserId): Promise<void>;
71
+ sendData<T>(receiverId: string | UserId, data: T): Promise<void>;
72
+ sendRelay(receiverId: string | UserId, data: Datagram): Promise<void>;
73
+ sendPing(receiverId: string | UserId): Promise<void>;
74
+ sendDiscover(receiverId: string | UserId, discoverId: string | UserId): Promise<void>;
75
+ sendBootstrap(receiverId: string | UserId): Promise<void>;
58
76
  protected decrypt(datagram: Datagram): Promise<Uint8Array>;
59
- /**
60
- * Open the datagram and execute operation of Discover and Handshake.
61
- *
62
- * @param datagram
63
- * @returns Header and decrypted payload
64
- */
65
- open(datagram: Datagram | Uint8Array): Promise<{
66
- header: DatagramHeader;
67
- payload?: Uint8Array;
68
- datagram?: Datagram;
69
- }>;
77
+ protected open(datagram: Datagram | Uint8Array): Promise<void>;
70
78
  }
71
79
  declare class SessionMap implements LocalStorage<string, KeySession> {
72
80
  readonly storage: LocalStorage<string, ExportedKeySession>;
package/dist/node.js CHANGED
@@ -49,31 +49,31 @@ const double_ratchet_1 = require("./double-ratchet");
49
49
  const _1 = require(".");
50
50
  const utils_1 = require("@freesignal/utils");
51
51
  const crypto_1 = __importDefault(require("@freesignal/crypto"));
52
- class BootstrapRequest {
53
- constructor(senderId, datagram) {
52
+ const easyemitter_ts_1 = __importDefault(require("easyemitter.ts"));
53
+ class BootstrapRequest extends easyemitter_ts_1.default {
54
+ constructor(senderId, keyExchangeData) {
55
+ super();
54
56
  this.senderId = senderId;
55
- this.datagram = datagram;
57
+ this.keyExchangeData = keyExchangeData;
56
58
  _BootstrapRequest_status.set(this, 'pending');
59
+ this.onChange = () => { };
60
+ this.on('change', (data) => this.onChange(data));
57
61
  }
58
62
  get status() {
59
63
  return __classPrivateFieldGet(this, _BootstrapRequest_status, "f");
60
64
  }
61
- get() {
62
- return __awaiter(this, void 0, void 0, function* () {
63
- return __classPrivateFieldGet(this, _BootstrapRequest_status, "f") === 'accepted' ? this.datagram : undefined;
64
- });
65
+ get data() {
66
+ return __classPrivateFieldGet(this, _BootstrapRequest_status, "f") === 'accepted' ? this.keyExchangeData : undefined;
65
67
  }
66
68
  accept() {
67
- return __awaiter(this, void 0, void 0, function* () {
68
- if (this.status === 'pending')
69
- __classPrivateFieldSet(this, _BootstrapRequest_status, 'accepted', "f");
70
- return yield this.get();
71
- });
69
+ if (this.status === 'pending')
70
+ __classPrivateFieldSet(this, _BootstrapRequest_status, 'accepted', "f");
71
+ this.emit('change', this);
72
72
  }
73
73
  deny() {
74
74
  if (this.status === 'pending')
75
75
  __classPrivateFieldSet(this, _BootstrapRequest_status, 'denied', "f");
76
- return;
76
+ this.emit('change', this);
77
77
  }
78
78
  }
79
79
  exports.BootstrapRequest = BootstrapRequest;
@@ -81,24 +81,38 @@ _BootstrapRequest_status = new WeakMap();
81
81
  class FreeSignalNode {
82
82
  constructor(storage, privateIdentityKey) {
83
83
  this.discovers = new Set();
84
- this.onRequest = () => { };
84
+ this.emitter = new easyemitter_ts_1.default();
85
+ this.onMessage = () => { };
86
+ this.onSend = () => { };
87
+ this.onHandshaked = () => { };
88
+ this.requests = {
89
+ onRequest: () => { },
90
+ getRequest: (userId) => {
91
+ return this.bootstraps.get(userId);
92
+ }
93
+ };
85
94
  this.privateIdentityKey = privateIdentityKey !== null && privateIdentityKey !== void 0 ? privateIdentityKey : (0, _1.createIdentity)();
86
95
  this.sessions = new SessionMap(storage.sessions);
87
96
  this.keyExchange = new x3dh_1.KeyExchange(storage.keyExchange, this.privateIdentityKey);
88
97
  this.bundles = storage.bundles;
89
98
  this.bootstraps = storage.bootstraps;
99
+ this.emitter.on('send', (data) => this.onSend(data.data.datagram.toBytes()));
100
+ this.emitter.on('handshaked', (data) => this.onHandshaked(types_1.UserId.from(data.data.header.sender)));
101
+ }
102
+ waitHandshaked(userId, timeout) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ var _a;
105
+ if (timeout)
106
+ setTimeout(() => { throw new Error(); }, timeout);
107
+ while (((_a = (yield this.emitter.wait('handshaked', timeout))) === null || _a === void 0 ? void 0 : _a.header.sender) !== userId.toString())
108
+ ;
109
+ });
90
110
  }
91
111
  get identityKey() {
92
112
  return this.privateIdentityKey.identityKey;
93
113
  }
94
114
  get userId() {
95
- return types_1.UserId.fromKey(this.identityKey);
96
- }
97
- getRequest(userId) {
98
- return __awaiter(this, void 0, void 0, function* () {
99
- var _a;
100
- return (_a = (yield this.bootstraps.get(userId))) === null || _a === void 0 ? void 0 : _a.get();
101
- });
115
+ return this.identityKey.userId;
102
116
  }
103
117
  encrypt(receiverId, protocol, data) {
104
118
  return __awaiter(this, void 0, void 0, function* () {
@@ -112,35 +126,50 @@ class FreeSignalNode {
112
126
  return new types_1.Datagram(this.userId.toString(), receiverId, protocol, encrypted).sign(this.privateIdentityKey.signatureKey);
113
127
  });
114
128
  }
115
- packHandshake(data) {
129
+ sendHandshake(data) {
116
130
  return __awaiter(this, void 0, void 0, function* () {
117
131
  var _a;
118
132
  if (typeof data === 'string' || data instanceof types_1.UserId) {
119
- //console.debug("Packing Handshake Ack");
133
+ //console.debug("Sending Handshake Ack");
120
134
  const userId = data.toString();
121
135
  const identityKey = (_a = (yield this.sessions.get(userId))) === null || _a === void 0 ? void 0 : _a.identityKey;
122
136
  if (!identityKey)
123
137
  throw new Error("Missing user");
124
- const res = yield this.encrypt(userId, types_1.Protocols.HANDSHAKE, crypto_1.default.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, identityKey.exchangeKey));
125
- return res;
138
+ const datagram = yield this.encrypt(userId, types_1.Protocols.HANDSHAKE, crypto_1.default.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, identityKey.exchangeKey));
139
+ this.emitter.emit('send', { header: datagram.header, datagram });
140
+ return;
126
141
  }
127
- //console.debug("Packing Handshake Syn");
142
+ //console.debug("Sending Handshake Syn");
128
143
  const { session, message } = yield this.keyExchange.digestData(data, (0, utils_1.encodeData)(yield this.keyExchange.generateBundle()));
129
144
  yield this.sessions.set(session.userId.toString(), session);
130
- return new types_1.Datagram(this.userId.toString(), types_1.UserId.fromKey(data.identityKey).toString(), types_1.Protocols.HANDSHAKE, (0, utils_1.encodeData)(message)).sign(this.privateIdentityKey.signatureKey);
145
+ const datagram = new types_1.Datagram(this.userId.toString(), types_1.UserId.fromKey(data.identityKey).toString(), types_1.Protocols.HANDSHAKE, (0, utils_1.encodeData)(message)).sign(this.privateIdentityKey.signatureKey);
146
+ this.emitter.emit('send', { header: datagram.header, datagram });
131
147
  });
132
148
  }
133
- packData(receiverId, data) {
134
- //console.debug("Packing Data");
135
- return this.encrypt(receiverId, types_1.Protocols.MESSAGE, (0, utils_1.encodeData)(data));
149
+ sendData(receiverId, data) {
150
+ return __awaiter(this, void 0, void 0, function* () {
151
+ //console.debug("Sending Data");
152
+ const datagram = yield this.encrypt(receiverId, types_1.Protocols.MESSAGE, (0, utils_1.encodeData)(data));
153
+ this.emitter.emit('send', { header: datagram.header, datagram });
154
+ });
136
155
  }
137
- packRelay(receiverId, data) {
138
- //console.debug("Packing Relay");
139
- return this.encrypt(receiverId, types_1.Protocols.RELAY, data.toBytes());
156
+ sendRelay(receiverId, data) {
157
+ return __awaiter(this, void 0, void 0, function* () {
158
+ //console.debug("Sending Relay");
159
+ const datagram = yield this.encrypt(receiverId, types_1.Protocols.RELAY, data.toBytes());
160
+ this.emitter.emit('send', { header: datagram.header, datagram });
161
+ });
162
+ }
163
+ sendPing(receiverId) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ //console.debug("Sending Ping");
166
+ const datagram = new types_1.Datagram(this.userId.toString(), receiverId.toString(), types_1.Protocols.PING);
167
+ this.emitter.emit('send', { header: datagram.header, datagram });
168
+ });
140
169
  }
141
- packDiscover(receiverId, discoverId) {
170
+ sendDiscover(receiverId, discoverId) {
142
171
  return __awaiter(this, void 0, void 0, function* () {
143
- //console.debug("Packing Discover");
172
+ //console.debug("Sending Discover");
144
173
  if (receiverId instanceof types_1.UserId)
145
174
  receiverId = receiverId.toString();
146
175
  if (discoverId instanceof types_1.UserId)
@@ -150,19 +179,15 @@ class FreeSignalNode {
150
179
  discoverId
151
180
  };
152
181
  this.discovers.add(receiverId);
153
- return this.encrypt(receiverId, types_1.Protocols.DISCOVER, (0, utils_1.encodeData)(message));
182
+ const datagram = yield this.encrypt(receiverId, types_1.Protocols.DISCOVER, (0, utils_1.encodeData)(message));
183
+ this.emitter.emit('send', { header: datagram.header, datagram });
154
184
  });
155
185
  }
156
- packBootstrap(receiverId) {
186
+ sendBootstrap(receiverId) {
157
187
  return __awaiter(this, void 0, void 0, function* () {
158
- //console.debug("Packing Bootstrap");
159
- return new types_1.Datagram(this.userId.toString(), receiverId.toString(), types_1.Protocols.BOOTSTRAP, (0, utils_1.encodeData)(yield this.keyExchange.generateData()));
160
- });
161
- }
162
- packGetBootstrap(receiverId) {
163
- return __awaiter(this, void 0, void 0, function* () {
164
- //console.debug("Packing GetBootstrap");
165
- return new types_1.Datagram(this.userId.toString(), receiverId.toString(), types_1.Protocols.BOOTSTRAP);
188
+ //console.debug("Sending Bootstrap");
189
+ const datagram = new types_1.Datagram(this.userId.toString(), receiverId.toString(), types_1.Protocols.BOOTSTRAP, (0, utils_1.encodeData)(yield this.keyExchange.generateData()));
190
+ this.emitter.emit('send', { header: datagram.header, datagram });
166
191
  });
167
192
  }
168
193
  decrypt(datagram) {
@@ -183,20 +208,11 @@ class FreeSignalNode {
183
208
  return decrypted;
184
209
  });
185
210
  }
186
- /**
187
- * Open the datagram and execute operation of Discover and Handshake.
188
- *
189
- * @param datagram
190
- * @returns Header and decrypted payload
191
- */
192
211
  open(datagram) {
193
212
  return __awaiter(this, void 0, void 0, function* () {
194
- var _a, _b;
213
+ var _a;
195
214
  if (datagram instanceof Uint8Array)
196
215
  datagram = types_1.Datagram.from(datagram);
197
- let out = {
198
- header: types_1.DatagramHeader.from(datagram.header)
199
- };
200
216
  switch (datagram.protocol) {
201
217
  case types_1.Protocols.HANDSHAKE:
202
218
  if (!datagram.payload)
@@ -209,7 +225,8 @@ class FreeSignalNode {
209
225
  throw new Error("Missing user");
210
226
  if (!(0, utils_1.compareBytes)(payload, crypto_1.default.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, identityKey.exchangeKey)))
211
227
  throw new Error("Error validating handshake data");
212
- return out;
228
+ this.emitter.emit('handshaked', { header: datagram.header });
229
+ return;
213
230
  }
214
231
  //console.debug("Opening Handshake Syn");
215
232
  const data = (0, utils_1.decodeData)(datagram.payload);
@@ -218,18 +235,17 @@ class FreeSignalNode {
218
235
  const { session, associatedData } = yield this.keyExchange.digestMessage(data);
219
236
  yield this.sessions.set(session.userId.toString(), session);
220
237
  yield this.bundles.set(session.userId.toString(), (0, utils_1.decodeData)(associatedData));
221
- out.datagram = yield this.packHandshake(session.userId);
222
- if (!out.datagram)
223
- throw new Error("Error during handshake");
224
- return out;
238
+ yield this.sendHandshake(session.userId);
239
+ this.emitter.emit('handshaked', { header: datagram.header });
240
+ return;
225
241
  case types_1.Protocols.MESSAGE:
226
242
  //console.debug("Opening Message");
227
- out.payload = yield this.decrypt(datagram);
228
- return out;
243
+ this.emitter.emit('message', { header: datagram.header, payload: yield this.decrypt(datagram) });
244
+ return;
229
245
  case types_1.Protocols.RELAY:
230
246
  //console.debug("Opening Relay");
231
- out.payload = yield this.decrypt(datagram);
232
- return out;
247
+ this.emitter.emit('send', { header: types_1.Datagram.from(yield this.decrypt(datagram)) });
248
+ return;
233
249
  case types_1.Protocols.DISCOVER:
234
250
  //console.debug("Opening Discover");
235
251
  const message = (0, utils_1.decodeData)(yield this.decrypt(datagram));
@@ -241,12 +257,12 @@ class FreeSignalNode {
241
257
  else {
242
258
  const bundle = yield this.bundles.get(message.discoverId);
243
259
  if (!bundle)
244
- return out;
260
+ return;
245
261
  const { version, identityKey, signedPreKey, signature } = bundle;
246
262
  const onetimePreKey = bundle.onetimePreKeys.shift();
247
263
  if (!onetimePreKey) {
248
264
  yield this.bundles.delete(message.discoverId);
249
- return out;
265
+ return;
250
266
  }
251
267
  data = {
252
268
  version,
@@ -257,31 +273,33 @@ class FreeSignalNode {
257
273
  };
258
274
  }
259
275
  const response = { type: types_1.DiscoverType.RESPONSE, discoverId: message.discoverId, data };
260
- out.datagram = yield this.encrypt(datagram.sender, types_1.Protocols.DISCOVER, (0, utils_1.encodeData)(response));
276
+ this.emitter.emit('send', yield this.encrypt(datagram.sender, types_1.Protocols.DISCOVER, (0, utils_1.encodeData)(response)));
261
277
  }
262
278
  else if (message.type === types_1.DiscoverType.RESPONSE && this.discovers.has(message.discoverId)) {
263
279
  this.discovers.delete(message.discoverId);
264
280
  if (message.data)
265
- out.datagram = yield this.packHandshake(message.data);
281
+ yield this.sendHandshake(message.data);
266
282
  }
267
- return out;
283
+ return;
268
284
  case types_1.Protocols.BOOTSTRAP:
269
285
  //console.debug("Opening Bootstrap");
270
- if (datagram.payload) {
271
- const data = (0, utils_1.decodeData)(datagram.payload);
272
- if (!(0, utils_1.compareBytes)(types_1.UserId.fromKey(data.identityKey).toBytes(), (0, utils_1.encodeBase64)(datagram.sender)))
273
- new Error("Malicious bootstrap request");
274
- const request = new BootstrapRequest(datagram.sender, yield this.packHandshake(data));
275
- yield this.bootstraps.set(datagram.sender, request);
276
- this.onRequest(request);
277
- }
278
- ;
279
- const handshakeDatagram = yield ((_b = (yield this.bootstraps.get(datagram.sender))) === null || _b === void 0 ? void 0 : _b.get());
280
- if (handshakeDatagram)
281
- out.datagram = handshakeDatagram;
282
- return out;
286
+ if (!datagram.payload)
287
+ throw new Error("Invalid Bootstrap");
288
+ const keyExchangeData = (0, utils_1.decodeData)(datagram.payload);
289
+ if (!(0, utils_1.compareBytes)(types_1.UserId.fromKey(keyExchangeData.identityKey).toBytes(), (0, utils_1.encodeBase64)(datagram.sender)))
290
+ new Error("Malicious bootstrap request");
291
+ const request = new BootstrapRequest(datagram.sender, keyExchangeData);
292
+ request.onChange = () => {
293
+ if (!request.data)
294
+ throw new Error("Error sending handshake");
295
+ this.sendHandshake(request.data);
296
+ };
297
+ yield this.bootstraps.set(datagram.sender, request);
298
+ this.requests.onRequest(request);
299
+ return;
283
300
  case types_1.Protocols.PING:
284
- return out;
301
+ this.emitter.emit('ping', { header: datagram.header });
302
+ return;
285
303
  default:
286
304
  throw new Error("Invalid protocol");
287
305
  }
package/dist/types.d.ts CHANGED
@@ -128,7 +128,7 @@ export declare class Datagram implements Encodable, DatagramHeader {
128
128
  get payload(): Uint8Array | undefined;
129
129
  get signature(): string | undefined;
130
130
  private get unsigned();
131
- get header(): Uint8Array;
131
+ get header(): DatagramHeader;
132
132
  toBytes(): Uint8Array;
133
133
  sign(secretKey: Uint8Array): SignedDatagram;
134
134
  toString(): string;
@@ -154,20 +154,31 @@ export declare class EncryptionHeader implements EncryptionKeys, Encodable {
154
154
  static from(data: Uint8Array | EncryptionHeader): EncryptionHeader;
155
155
  }
156
156
  export declare class EncryptedData implements Encodable {
157
- readonly header: Uint8Array;
158
- readonly nonce: Uint8Array;
159
- readonly payload: Uint8Array;
160
157
  static readonly version = 1;
161
158
  static readonly nonceLength: number;
162
159
  private _version;
163
- constructor(header: Uint8Array, nonce: Uint8Array, payload: Uint8Array);
160
+ readonly header: Uint8Array;
161
+ readonly hashkey?: Uint8Array;
162
+ readonly nonce?: Uint8Array;
163
+ readonly payload: Uint8Array;
164
+ constructor(opts: {
165
+ header: Uint8Array;
166
+ payload: Uint8Array;
167
+ });
168
+ constructor(opts: {
169
+ header: Uint8Array;
170
+ hashkey: Uint8Array;
171
+ nonce: Uint8Array;
172
+ payload: Uint8Array;
173
+ });
164
174
  get version(): number;
165
175
  get length(): number;
166
176
  toBytes(): Uint8Array;
167
177
  toJSON(): {
168
178
  version: number;
169
179
  header: string;
170
- nonce: string;
180
+ hashkey?: string;
181
+ nonce?: string;
171
182
  payload: string;
172
183
  };
173
184
  static from(data: Uint8Array | EncryptedData): EncryptedData;
package/dist/types.js CHANGED
@@ -35,66 +35,34 @@ exports.encryptData = encryptData;
35
35
  exports.decryptData = decryptData;
36
36
  const utils_1 = require("@freesignal/utils");
37
37
  const crypto_1 = __importDefault(require("@freesignal/crypto"));
38
- /*export function encryptData(session: KeySession, data: Uint8Array): EncryptedData {
38
+ function encryptData(session, data) {
39
39
  const key = session.getSendingKey();
40
40
  if (!key)
41
41
  throw new Error("Error generating key");
42
- const nonce = crypto.randomBytes(EncryptionHeader.nonceLength);
43
- const ciphertext = crypto.box.encrypt(data, nonce, key.secretKey);
44
- const headerKey = session.getHeaderKeys().sending;
45
- //console.debug(session.userId.toString(), "Sending: ", decodeBase64(headerKey ?? new Uint8Array()))
42
+ const nonce = crypto_1.default.randomBytes(EncryptionHeader.nonceLength);
43
+ const payload = crypto_1.default.box.encrypt(data, nonce, key.secretKey);
46
44
  let header = new EncryptionHeader(key, nonce).toBytes();
47
- const headerNonce = crypto.randomBytes(EncryptionHeader.nonceLength)
45
+ const headerKey = session.getHeaderKey();
46
+ if (!headerKey)
47
+ return new EncryptedData({ header, payload });
48
+ const headerNonce = crypto_1.default.randomBytes(EncryptionHeader.nonceLength);
48
49
  if (headerKey)
49
- header = crypto.box.encrypt(header, headerNonce, headerKey);
50
- const test = new EncryptedData(header, headerNonce, ciphertext);
51
- return test;
50
+ header = crypto_1.default.box.encrypt(header, headerNonce, headerKey);
51
+ return new EncryptedData({ hashkey: crypto_1.default.hash(headerKey !== null && headerKey !== void 0 ? headerKey : new Uint8Array(32).fill(0)), header, nonce: headerNonce, payload });
52
52
  }
53
-
54
- export function decryptData(session: KeySession, encryptedData: Uint8Array): Uint8Array {
53
+ function decryptData(session, encryptedData) {
55
54
  const encrypted = EncryptedData.from(encryptedData);
56
- const headerKey = session.getHeaderKeys().receiving;
57
- const nextHeaderKey = session.getHeaderKeys().nextReciving;
58
- let headerData: Uint8Array | undefined;
59
- try {
55
+ let headerData = encrypted.header;
56
+ if (encrypted.hashkey && encrypted.nonce) {
57
+ const headerKey = session.getHeaderKey((0, utils_1.decodeBase64)(encrypted.hashkey));
60
58
  if (!headerKey)
61
- throw new Error("Error generating key");
62
- headerData = crypto.box.decrypt(encrypted.header, encrypted.nonce, headerKey);
63
- if (!headerData)
59
+ throw new Error("Error getting key");
60
+ const data = crypto_1.default.box.decrypt(encrypted.header, encrypted.nonce, headerKey);
61
+ if (!data)
64
62
  throw new Error("Error calculating header");
65
- //console.debug(session.userId.toString(), "Receiving: ", decodeBase64(session.getHeaderKeys().receiving ?? new Uint8Array()))
66
- } catch {
67
- if (!nextHeaderKey)
68
- throw new Error("Error generating key");
69
- headerData = crypto.box.decrypt(encrypted.header, encrypted.nonce, nextHeaderKey);
70
- if (!headerData) {
71
- //console.debug(session.toJSON());
72
- throw new Error("Error calculating header");
73
- }
74
- //console.debug(session.userId.toString(), "NextReceiving: ", decodeBase64(session.getHeaderKeys().nextReciving ?? new Uint8Array()))
63
+ headerData = data;
75
64
  }
76
- const header = EncryptionHeader.from(headerData!);
77
- const key = session.getReceivingKey(header);
78
- if (!key)
79
- throw new Error("Error calculating key");
80
- const decrypted = crypto.box.decrypt(encrypted.payload, header.nonce, key);
81
- if (!decrypted)
82
- throw new Error("Error decrypting data");
83
- return decrypted;
84
- }*/
85
- function encryptData(session, data) {
86
- const key = session.getSendingKey();
87
- if (!key)
88
- throw new Error("Error generating key");
89
- const nonce = crypto_1.default.randomBytes(EncryptionHeader.nonceLength);
90
- const ciphertext = crypto_1.default.box.encrypt(data, nonce, key.secretKey);
91
- let header = new EncryptionHeader(key, nonce).toBytes();
92
- const test = new EncryptedData(header, crypto_1.default.randomBytes(EncryptionHeader.nonceLength), ciphertext);
93
- return test;
94
- }
95
- function decryptData(session, encryptedData) {
96
- const encrypted = EncryptedData.from(encryptedData);
97
- const header = EncryptionHeader.from(encrypted.header);
65
+ const header = EncryptionHeader.from(headerData);
98
66
  const key = session.getReceivingKey(header);
99
67
  if (!key)
100
68
  throw new Error("Error calculating key");
@@ -318,7 +286,7 @@ class Datagram {
318
286
  return data.subarray(0, data.length - (this._signature ? crypto_1.default.EdDSA.signatureLength : 0));
319
287
  }
320
288
  get header() {
321
- return this.toBytes().slice(0, DatagramHeader.headerLength);
289
+ return DatagramHeader.from(this.toBytes().slice(0, DatagramHeader.headerLength));
322
290
  }
323
291
  toBytes() {
324
292
  var _a, _b, _c;
@@ -400,11 +368,12 @@ class EncryptionHeader {
400
368
  static from(data) {
401
369
  if (data instanceof EncryptionHeader)
402
370
  data = data.toBytes();
371
+ let offset = 0;
403
372
  return new EncryptionHeader({
404
- count: (0, utils_1.bytesToNumber)(data.subarray(0, EncryptionHeader.countLength)),
405
- previous: (0, utils_1.bytesToNumber)(data.subarray(EncryptionHeader.countLength, EncryptionHeader.countLength * 2)),
406
- publicKey: data.subarray(EncryptionHeader.countLength * 2, EncryptionHeader.countLength * 2 + EncryptionHeader.keyLength)
407
- }, data.subarray(EncryptionHeader.countLength * 2 + EncryptionHeader.keyLength, EncryptionHeader.countLength * 2 + EncryptionHeader.keyLength + EncryptedData.nonceLength));
373
+ count: (0, utils_1.bytesToNumber)(data.subarray(offset, offset += EncryptionHeader.countLength)),
374
+ previous: (0, utils_1.bytesToNumber)(data.subarray(offset, offset += EncryptionHeader.countLength)),
375
+ publicKey: data.subarray(offset, offset += EncryptionHeader.keyLength)
376
+ }, data.subarray(offset, offset += EncryptedData.nonceLength));
408
377
  }
409
378
  }
410
379
  exports.EncryptionHeader = EncryptionHeader;
@@ -412,11 +381,12 @@ EncryptionHeader.keyLength = crypto_1.default.box.keyLength;
412
381
  EncryptionHeader.nonceLength = crypto_1.default.box.nonceLength;
413
382
  EncryptionHeader.countLength = 2;
414
383
  class EncryptedData {
415
- constructor(header, nonce, payload) {
384
+ constructor({ hashkey, header, nonce, payload }) {
385
+ this._version = EncryptedData.version;
416
386
  this.header = header;
387
+ this.hashkey = hashkey;
417
388
  this.nonce = nonce;
418
389
  this.payload = payload;
419
- this._version = EncryptedData.version;
420
390
  }
421
391
  get version() {
422
392
  return this._version;
@@ -425,22 +395,36 @@ class EncryptedData {
425
395
  return this.toBytes().length;
426
396
  }
427
397
  toBytes() {
428
- return (0, utils_1.concatBytes)((0, utils_1.numberToBytes)(this._version, 1), (0, utils_1.numberToBytes)(this.header.length, 3), this.header, this.nonce, this.payload);
398
+ var _a, _b;
399
+ return (0, utils_1.concatBytes)((0, utils_1.numberToBytes)(this._version | (this.hashkey && this.nonce ? 128 : 0), 1), (0, utils_1.numberToBytes)(this.header.length, 3), this.header, (_a = this.hashkey) !== null && _a !== void 0 ? _a : new Uint8Array(), (_b = this.nonce) !== null && _b !== void 0 ? _b : new Uint8Array, this.payload);
429
400
  }
430
401
  toJSON() {
431
402
  return {
432
403
  version: this._version,
433
404
  header: (0, utils_1.decodeBase64)(this.header),
434
- nonce: (0, utils_1.decodeBase64)(this.nonce),
405
+ hashkey: this.hashkey ? (0, utils_1.decodeBase64)(this.hashkey) : undefined,
406
+ nonce: this.nonce ? (0, utils_1.decodeBase64)(this.nonce) : undefined,
435
407
  payload: (0, utils_1.decodeBase64)(this.payload)
436
408
  };
437
409
  }
438
410
  static from(data) {
439
411
  if (data instanceof EncryptedData)
440
412
  data = data.toBytes();
413
+ const versionByte = (0, utils_1.bytesToNumber)(data.subarray(0, 1));
441
414
  const headerLength = (0, utils_1.bytesToNumber)(data.subarray(1, 4));
442
- const obj = new EncryptedData(data.subarray(4, 4 + headerLength), data.subarray(4 + headerLength, 4 + headerLength + this.nonceLength), data.subarray(4 + headerLength + this.nonceLength));
443
- obj._version = (0, utils_1.bytesToNumber)(data.subarray(0, 1));
415
+ let offset = 4;
416
+ const header = data.subarray(offset, offset += headerLength);
417
+ let hashkey, nonce;
418
+ if ((versionByte & 128) > 0) {
419
+ hashkey = data.subarray(offset, offset += 32);
420
+ nonce = data.subarray(offset, offset += this.nonceLength);
421
+ }
422
+ const payload = data.subarray(offset);
423
+ if (!hashkey || !nonce)
424
+ var obj = new EncryptedData({ header, payload });
425
+ else
426
+ var obj = new EncryptedData({ header, hashkey, nonce, payload });
427
+ obj._version = versionByte & 127;
444
428
  return obj;
445
429
  }
446
430
  }
package/dist/x3dh.js CHANGED
@@ -99,8 +99,7 @@ class KeyExchange {
99
99
  ...crypto_1.default.ECDH.scalarMult(ephemeralKey.secretKey, signedPreKey),
100
100
  ...onetimePreKey ? crypto_1.default.ECDH.scalarMult(ephemeralKey.secretKey, onetimePreKey) : new Uint8Array()
101
101
  ]), new Uint8Array(double_ratchet_1.KeySession.keyLength).fill(0), KeyExchange.hkdfInfo, double_ratchet_1.KeySession.keyLength * 3);
102
- //, headerKey: derivedKey.subarray(KeySession.keyLength, KeySession.keyLength * 2), nextHeaderKey: derivedKey.subarray(KeySession.keyLength * 2)
103
- const session = new double_ratchet_1.KeySession({ identityKey, remoteKey: identityKey.exchangeKey, rootKey: derivedKey.subarray(0, double_ratchet_1.KeySession.keyLength) });
102
+ const session = new double_ratchet_1.KeySession({ identityKey, remoteKey: identityKey.exchangeKey, rootKey: derivedKey.subarray(0, double_ratchet_1.KeySession.keyLength), headerKey: derivedKey.subarray(double_ratchet_1.KeySession.keyLength, double_ratchet_1.KeySession.keyLength * 2), nextHeaderKey: derivedKey.subarray(double_ratchet_1.KeySession.keyLength * 2) });
104
103
  const encrypted = (0, types_1.encryptData)(session, (0, utils_1.concatBytes)(crypto_1.default.hash(this.identityKey.toBytes()), crypto_1.default.hash(identityKey.toBytes()), associatedData !== null && associatedData !== void 0 ? associatedData : new Uint8Array()));
105
104
  if (!encrypted)
106
105
  throw new Error("Decryption error");
@@ -135,8 +134,7 @@ class KeyExchange {
135
134
  ...crypto_1.default.ECDH.scalarMult(signedPreKey.secretKey, ephemeralKey),
136
135
  ...onetimePreKey ? crypto_1.default.ECDH.scalarMult(onetimePreKey.secretKey, ephemeralKey) : new Uint8Array()
137
136
  ]), new Uint8Array(double_ratchet_1.KeySession.keyLength).fill(0), KeyExchange.hkdfInfo, double_ratchet_1.KeySession.keyLength * 3);
138
- //nextHeaderKey: derivedKey.subarray(KeySession.keyLength, KeySession.keyLength * 2), headerKey: derivedKey.subarray(KeySession.keyLength * 2)
139
- const session = new double_ratchet_1.KeySession({ identityKey, secretKey: this.privateIdentityKey.exchangeKey, rootKey: derivedKey.subarray(0, double_ratchet_1.KeySession.keyLength) });
137
+ const session = new double_ratchet_1.KeySession({ identityKey, secretKey: this.privateIdentityKey.exchangeKey, rootKey: derivedKey.subarray(0, double_ratchet_1.KeySession.keyLength), nextHeaderKey: derivedKey.subarray(double_ratchet_1.KeySession.keyLength, double_ratchet_1.KeySession.keyLength * 2), headerKey: derivedKey.subarray(double_ratchet_1.KeySession.keyLength * 2) });
140
138
  const data = (0, types_1.decryptData)(session, (0, utils_1.encodeBase64)(message.associatedData));
141
139
  if (!data)
142
140
  throw new Error("Error decrypting ACK message");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesignal/protocol",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Signal Protocol implementation in javascript",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Christian Braghette",
@@ -37,9 +37,10 @@
37
37
  "@freesignal/crypto": "^0.3.0",
38
38
  "@freesignal/interfaces": "^0.2.0",
39
39
  "@freesignal/utils": "^1.4.1",
40
+ "easyemitter.ts": "^1.0.3",
40
41
  "semaphore.ts": "^0.2.0"
41
42
  },
42
43
  "devDependencies": {
43
44
  "@types/node": "^24.2.1"
44
45
  }
45
- }
46
+ }
package/dist/test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/test.js DELETED
@@ -1,48 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const utils_1 = require("@freesignal/utils");
13
- const _1 = require(".");
14
- console.log("FreeSignal protocol test");
15
- const bob = (0, _1.createNode)({ keyExchange: new _1.AsyncMap(), sessions: new _1.AsyncMap(), users: new _1.AsyncMap(), bundles: new _1.AsyncMap(), bootstraps: new _1.AsyncMap() });
16
- const alice = (0, _1.createNode)({ keyExchange: new _1.AsyncMap(), sessions: new _1.AsyncMap(), users: new _1.AsyncMap(), bundles: new _1.AsyncMap(), bootstraps: new _1.AsyncMap() });
17
- setImmediate(() => __awaiter(void 0, void 0, void 0, function* () {
18
- const bobBootstrap = yield bob.packBootstrap(alice.userId);
19
- alice.onRequest = (request) => { request.accept(); };
20
- const test = (yield alice.open(bobBootstrap)).datagram;
21
- const aliceHandshake = yield alice.getRequest(bob.userId.toString());
22
- if (!aliceHandshake)
23
- throw new Error("Bootstrap Failed");
24
- const bobHandshake = (yield bob.open(aliceHandshake)).datagram;
25
- if (!bobHandshake)
26
- throw new Error("Handshake Failed");
27
- console.log(!!(yield alice.open(bobHandshake)).header);
28
- const first = (yield bob.packData(alice.userId, "Hi Alice!")).toBytes();
29
- console.log("Bob: ", (0, utils_1.decodeData)((yield alice.open(first)).payload));
30
- const second = yield alice.packData(bob.userId, "Hi Bob!");
31
- console.log("Test");
32
- console.log("Alice: ", (0, utils_1.decodeData)((yield bob.open(second)).payload));
33
- const third = yield Promise.all(["How are you?", "How are this days?", "For me it's a good time"].map(msg => bob.packData(alice.userId, msg)));
34
- third.forEach((data) => __awaiter(void 0, void 0, void 0, function* () {
35
- console.log("Bob: ", (0, utils_1.decodeData)((yield alice.open(data)).payload));
36
- }));
37
- const fourth = yield alice.packData(bob.userId, "Not so bad my man");
38
- console.log("Alice: ", (0, utils_1.decodeData)((yield bob.open(fourth)).payload));
39
- const fifth = yield Promise.all(["I'm thinking...", "His this secure?"].map(msg => bob.packData(alice.userId, msg)));
40
- fifth.forEach((data) => __awaiter(void 0, void 0, void 0, function* () {
41
- console.log("Bob: ", (0, utils_1.decodeData)((yield alice.open(data)).payload));
42
- }));
43
- const msg = yield alice.packData(bob.userId, (0, utils_1.encodeData)("test"));
44
- const relay = yield alice.packRelay(bob.userId, msg);
45
- console.log((0, utils_1.compareBytes)(msg.toBytes(), (yield bob.open(relay)).payload));
46
- //const testone = await Promise.all(Array(400).fill(0).map(() => alice.packData(bob.userId, decodeBase64(crypto.randomBytes(64)))));
47
- //console.log(((await bob.open(testone[350])).payload));
48
- }));