@wireapp/core-crypto 0.5.2 → 0.6.0-pre.2

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -55,9 +55,10 @@ rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
55
55
 
56
56
  ### MacOS
57
57
 
58
- Install macOS rust targets (M1 macs are currently not supported)
58
+ Install macOS rust targets
59
59
  ```ignore
60
60
  rustup target add x86_64-apple-darwin
61
+ rustup target add aarch64-apple-darwin
61
62
  ```
62
63
 
63
64
  ### Linux
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wireapp/core-crypto",
3
- "version": "0.5.2",
3
+ "version": "0.6.0-pre.2",
4
4
  "description": "CoreCrypto bindings for the Web",
5
5
  "type": "module",
6
6
  "module": "platforms/web/corecrypto.js",
@@ -68,16 +68,6 @@ export declare type ClientId = Uint8Array;
68
68
  * Alias for proposal reference. It is a byte array of size 16.
69
69
  */
70
70
  export declare type ProposalRef = Uint8Array;
71
- /**
72
- * Alias for an MLS generic commit.
73
- * It contains:
74
- * * MLS Commit that needs to be fanned out to other (existing) members of the conversation
75
- * * (Optional) MLS Welcome message that needs to be fanned out to the clients newly added to the conversation (if any)
76
- * * TLS-serialized MLS PublicGroupState (GroupInfo in draft-15) which is required for joining a group by external commit + some metadatas for optimizations
77
- * (For final version. Requires to be implemented in the Delivery Service)
78
- * This is a freeform, uninspected buffer.
79
- */
80
- export declare type TlsCommitBundle = Uint8Array;
81
71
  /**
82
72
  * Data shape for the returned MLS commit & welcome message tuple upon adding clients to a conversation
83
73
  */
@@ -95,11 +85,11 @@ export interface MemberAddedMessages {
95
85
  */
96
86
  welcome: Uint8Array;
97
87
  /**
98
- * TLS-serialized MLS PublicGroupState (GroupInfo in draft-15) which is required for joining a group by external commit
88
+ * MLS PublicGroupState (GroupInfo in draft-15) which is required for joining a group by external commit
99
89
  *
100
90
  * @readonly
101
91
  */
102
- publicGroupState: Uint8Array;
92
+ publicGroupState: PublicGroupStateBundle;
103
93
  }
104
94
  /**
105
95
  * Data shape for a MLS generic commit + optional bundle (aka stapled commit & welcome)
@@ -118,11 +108,61 @@ export interface CommitBundle {
118
108
  */
119
109
  welcome?: Uint8Array;
120
110
  /**
121
- * TLS-serialized MLS PublicGroupState (GroupInfo in draft-15) which is required for joining a group by external commit
111
+ * MLS PublicGroupState (GroupInfo in draft-15) which is required for joining a group by external commit
122
112
  *
123
113
  * @readonly
124
114
  */
125
- publicGroupState: Uint8Array;
115
+ publicGroupState: PublicGroupStateBundle;
116
+ }
117
+ /**
118
+ * Wraps a PublicGroupState in order to efficiently upload it to the Delivery Service.
119
+ * This is not part of MLS protocol but parts might be standardized at some point.
120
+ */
121
+ export interface PublicGroupStateBundle {
122
+ /**
123
+ * see {@link PublicGroupStateEncryptionType}
124
+ */
125
+ encryptionType: PublicGroupStateEncryptionType;
126
+ /**
127
+ * see {@link RatchetTreeType}
128
+ */
129
+ ratchetTreeType: RatchetTreeType;
130
+ /**
131
+ * TLS-serialized PublicGroupState
132
+ */
133
+ payload: Uint8Array;
134
+ }
135
+ /**
136
+ * Informs whether the PublicGroupState is confidential
137
+ * see [core_crypto::mls::conversation::public_group_state::PublicGroupStateEncryptionType]
138
+ */
139
+ export declare enum PublicGroupStateEncryptionType {
140
+ /**
141
+ * Unencrypted
142
+ */
143
+ Plaintext = 1,
144
+ /**
145
+ * Encrypted in a JWE (not yet implemented)
146
+ */
147
+ JweEncrypted = 2
148
+ }
149
+ /**
150
+ * Represents different ways of carrying the Ratchet Tree with some optimizations to save some space
151
+ * see [core_crypto::mls::conversation::public_group_state::RatchetTreeType]
152
+ */
153
+ export declare enum RatchetTreeType {
154
+ /**
155
+ * Complete PublicGroupState
156
+ */
157
+ Full = 1,
158
+ /**
159
+ * Contains the difference since previous epoch (not yet implemented)
160
+ */
161
+ Delta = 2,
162
+ /**
163
+ * To define (not yet implemented)
164
+ */
165
+ ByRef = 3
126
166
  }
127
167
  /**
128
168
  * Params for CoreCrypto initialization
@@ -166,19 +206,26 @@ export interface Invitee {
166
206
  */
167
207
  kp: Uint8Array;
168
208
  }
169
- export interface MlsConversationInitMessage {
209
+ export interface ConversationInitBundle {
170
210
  /**
171
- * Group ID
211
+ * Conversation ID of the conversation created
172
212
  *
173
213
  * @readonly
174
214
  */
175
- group: Uint8Array;
215
+ conversationId: ConversationId;
176
216
  /**
177
- * TLS-serialized MLS Commit that needs to be fanned out
217
+ * TLS-serialized MLS External Commit that needs to be fanned out
178
218
  *
179
219
  * @readonly
180
220
  */
181
221
  commit: Uint8Array;
222
+ /**
223
+ * MLS Public Group State (aka Group Info) which becomes valid when the external commit is accepted by the Delivery Service
224
+ * with {@link CoreCrypto.mergePendingGroupFromExternalCommit}
225
+ *
226
+ * @readonly
227
+ */
228
+ publicGroupState: PublicGroupStateBundle;
182
229
  }
183
230
  /**
184
231
  * This is a wrapper for all the possible outcomes you can get after decrypting a message
@@ -207,6 +254,10 @@ export interface DecryptedMessage {
207
254
  * Client identifier of the sender of the message being decrypted. Only present for application messages.
208
255
  */
209
256
  senderClientId?: ClientId;
257
+ /**
258
+ * true when the decrypted message resulted in an epoch change i.e. it was a commit
259
+ */
260
+ hasEpochChanged: boolean;
210
261
  }
211
262
  /**
212
263
  * Returned by all methods creating proposals. Contains a proposal message and an identifier to roll back the proposal
@@ -305,7 +356,7 @@ export interface CoreCryptoCallbacks {
305
356
  * in the given conversationId. Think of it as a "isAdmin" callback conceptually
306
357
  *
307
358
  * This callback exists because there are many business cases where CoreCrypto doesn't have enough knowledge
308
- * (such as what can exists on a backend) to inform the decision
359
+ * (such as what can exist on a backend) to inform the decision
309
360
  *
310
361
  * @param conversationId - id of the group/conversation
311
362
  * @param clientId - id of the client performing an operation requiring authorization
@@ -313,10 +364,25 @@ export interface CoreCryptoCallbacks {
313
364
  */
314
365
  authorize: (conversationId: Uint8Array, clientId: Uint8Array) => boolean;
315
366
  /**
316
- * Callback to ensure that the given `clientId` belongs to one of the provided `otherClients`
367
+ * A mix between {@link authorize} and {@link clientIsExistingGroupUser}. We currently use this callback to verify
368
+ * external commits to join a group ; in such case, the client has to:
369
+ * * first, belong to a user which is already in the MLS group (similar to {@link clientIsExistingGroupUser})
370
+ * * then, this user should be authorized to "write" in the given conversation (similar to {@link authorize})
371
+ *
372
+ * @param conversationId - id of the group/conversation
373
+ * @param externalClientId - id of the client performing an operation requiring authorization
374
+ * @param existingClients - all the clients currently within the MLS group
375
+ * @returns true if the external client is authorized to write to the conversation
376
+ */
377
+ userAuthorize: (conversationId: Uint8Array, externalClientId: Uint8Array, existingClients: Uint8Array[]) => boolean;
378
+ /**
379
+ * Callback to ensure that the given `clientId` belongs to one of the provided `existingClients`
317
380
  * This basically allows to defer the client ID parsing logic to the caller - because CoreCrypto is oblivious to such things
381
+ *
382
+ * @param clientId - id of a client
383
+ * @param existingClients - all the clients currently within the MLS group
318
384
  */
319
- clientIdBelongsToOneOf: (clientId: Uint8Array, otherClients: Uint8Array[]) => boolean;
385
+ clientIsExistingGroupUser: (clientId: Uint8Array, existingClients: Uint8Array[]) => boolean;
320
386
  }
321
387
  /**
322
388
  * Wrapper for the WASM-compiled version of CoreCrypto
@@ -515,72 +581,6 @@ export declare class CoreCrypto {
515
581
  * @returns A {@link CommitBundle} or `undefined` when there was no pending proposal to commit
516
582
  */
517
583
  commitPendingProposals(conversationId: ConversationId): Promise<CommitBundle | undefined>;
518
- /**
519
- * Adds new clients to a conversation, assuming the current client has the right to add new clients to the conversation.
520
- * The returned {@link CommitBundle} is a TLS struct that needs to be fanned out to Delivery Service in order to validate the commit.
521
- * It also contains a Welcome message the Delivery Service will forward to invited clients and
522
- * an updated PublicGroupState required by clients willing to join the group by an external commit.
523
- *
524
- * **CAUTION**: {@link CoreCrypto.commitAccepted} **HAS TO** be called afterwards **ONLY IF** the Delivery Service responds
525
- * '200 OK' to the {@link CommitBundle} upload. It will "merge" the commit locally i.e. increment the local group
526
- * epoch, use new encryption secrets etc...
527
- *
528
- * @param conversationId - The ID of the conversation
529
- * @param clients - Array of {@link Invitee} (which are Client ID / KeyPackage pairs)
530
- *
531
- * @returns A {@link CommitBundle} byte array to fan out to the Delivery Service
532
- */
533
- finalAddClientsToConversation(conversationId: ConversationId, clients: Invitee[]): Promise<TlsCommitBundle>;
534
- /**
535
- * Removes the provided clients from a conversation; Assuming those clients exist and the current client is allowed
536
- * to do so, otherwise this operation does nothing.
537
- *
538
- * The returned {@link CommitBundle} is a TLS struct that needs to be fanned out to Delivery Service in order to validate the commit.
539
- * It also contains a Welcome message the Delivery Service will forward to invited clients and
540
- * an updated PublicGroupState required by clients willing to join the group by an external commit.
541
- *
542
- * **CAUTION**: {@link CoreCrypto.commitAccepted} **HAS TO** be called afterwards **ONLY IF** the Delivery Service responds
543
- * '200 OK' to the {@link CommitBundle} upload. It will "merge" the commit locally i.e. increment the local group
544
- * epoch, use new encryption secrets etc...
545
- *
546
- * @param conversationId - The ID of the conversation
547
- * @param clientIds - Array of Client IDs to remove.
548
- *
549
- * @returns A {@link CommitBundle} byte array to fan out to the Delivery Service, or `undefined` if for any reason, the operation would result in an empty commit
550
- */
551
- finalRemoveClientsFromConversation(conversationId: ConversationId, clientIds: ClientId[]): Promise<TlsCommitBundle>;
552
- /**
553
- * Creates an update commit which forces every client to update their keypackages in the conversation
554
- *
555
- * The returned {@link CommitBundle} is a TLS struct that needs to be fanned out to Delivery Service in order to validate the commit.
556
- * It also contains a Welcome message the Delivery Service will forward to invited clients and
557
- * an updated PublicGroupState required by clients willing to join the group by an external commit.
558
- *
559
- * **CAUTION**: {@link CoreCrypto.commitAccepted} **HAS TO** be called afterwards **ONLY IF** the Delivery Service responds
560
- * '200 OK' to the {@link CommitBundle} upload. It will "merge" the commit locally i.e. increment the local group
561
- * epoch, use new encryption secrets etc...
562
- *
563
- * @param conversationId - The ID of the conversation
564
- *
565
- * @returns A {@link CommitBundle} byte array to fan out to the Delivery Service
566
- */
567
- finalUpdateKeyingMaterial(conversationId: ConversationId): Promise<TlsCommitBundle>;
568
- /**
569
- * Commits the local pending proposals and returns the {@link CommitBundle} object containing what can result from this operation.
570
- *
571
- * The returned {@link CommitBundle} is a TLS struct that needs to be fanned out to Delivery Service in order to validate the commit.
572
- * It also contains a Welcome message the Delivery Service will forward to invited clients and
573
- * an updated PublicGroupState required by clients willing to join the group by an external commit.
574
- *
575
- * **CAUTION**: {@link CoreCrypto.commitAccepted} **HAS TO** be called afterwards **ONLY IF** the Delivery Service responds
576
- * '200 OK' to the {@link CommitBundle} upload. It will "merge" the commit locally i.e. increment the local group
577
- * epoch, use new encryption secrets etc...
578
- *
579
- * @param conversationId - The ID of the conversation
580
- *
581
- * @returns A {@link CommitBundle} byte array to fan out to the Delivery Service or `undefined` when there was no pending proposal to commit
582
- */
583
- finalCommitPendingProposals(conversationId: ConversationId): Promise<TlsCommitBundle | undefined>;
584
584
  /**
585
585
  * Creates a new proposal for the provided Conversation ID
586
586
  *
@@ -599,23 +599,35 @@ export declare class CoreCrypto {
599
599
  */
600
600
  exportGroupState(conversationId: ConversationId): Promise<Uint8Array>;
601
601
  /**
602
- * Allows to create an external commit to "apply" to join a group through its public group state
602
+ * Allows to create an external commit to "apply" to join a group through its public group state.
603
603
  *
604
- * Also see the second step of this process: {@link CoreCrypto.mergePendingGroupFromExternalCommit}
604
+ * If the Delivery Service accepts the external commit, you have to {@link CoreCrypto.mergePendingGroupFromExternalCommit}
605
+ * in order to get back a functional MLS group. On the opposite, if it rejects it, you can either retry by just
606
+ * calling again {@link CoreCrypto.joinByExternalCommit}, no need to {@link CoreCrypto.clearPendingGroupFromExternalCommit}.
607
+ * If you want to abort the operation (too many retries or the user decided to abort), you can use
608
+ * {@link CoreCrypto.clearPendingGroupFromExternalCommit} in order not to bloat the user's storage but nothing
609
+ * bad can happen if you forget to except some storage space wasted.
605
610
  *
606
- * @param publicGroupState - The public group state that can be fetched from the backend for a given conversation
607
- * @returns see {@link MlsConversationInitMessage}
611
+ * @param publicGroupState - a TLS encoded PublicGroupState fetched from the Delivery Service
612
+ * @returns see {@link ConversationInitBundle}
608
613
  */
609
- joinByExternalCommit(publicGroupState: Uint8Array): Promise<MlsConversationInitMessage>;
614
+ joinByExternalCommit(publicGroupState: Uint8Array): Promise<ConversationInitBundle>;
610
615
  /**
611
- * This is the second step of the process of joining a group through an external commit
612
- *
613
- * This step makes the group operational and ready to encrypt/decrypt message
616
+ * This merges the commit generated by {@link CoreCrypto.joinByExternalCommit}, persists the group permanently
617
+ * and deletes the temporary one. This step makes the group operational and ready to encrypt/decrypt message
614
618
  *
615
619
  * @param conversationId - The ID of the conversation
616
620
  * @param configuration - Configuration of the group, see {@link ConversationConfiguration}
617
621
  */
618
622
  mergePendingGroupFromExternalCommit(conversationId: ConversationId, configuration: ConversationConfiguration): Promise<void>;
623
+ /**
624
+ * In case the external commit generated by {@link CoreCrypto.joinByExternalCommit} is rejected by the Delivery Service, and we
625
+ * want to abort this external commit once for all, we can wipe out the pending group from the keystore in order
626
+ * not to waste space
627
+ *
628
+ * @param conversationId - The ID of the conversation
629
+ */
630
+ clearPendingGroupFromExternalCommit(conversationId: ConversationId): Promise<void>;
619
631
  /**
620
632
  * Allows to mark the latest commit produced as "accepted" and be able to safely merge it
621
633
  * into the local group state
@@ -646,6 +658,24 @@ export declare class CoreCrypto {
646
658
  * @param conversationId - The group's ID
647
659
  */
648
660
  clearPendingCommit(conversationId: ConversationId): Promise<void>;
661
+ /**
662
+ * Derives a new key from the group
663
+ *
664
+ * @param conversationId - The group's ID
665
+ * @param keyLength - the length of the key to be derived. If the value is higher than the
666
+ * bounds of `u16` or the context hash * 255, an error will be returned
667
+ *
668
+ * @returns A `Uint8Array` representing the derived key
669
+ */
670
+ exportSecretKey(conversationId: ConversationId, keyLength: number): Promise<Uint8Array>;
671
+ /**
672
+ * Returns all clients from group's members
673
+ *
674
+ * @param conversationId - The group's ID
675
+ *
676
+ * @returns A list of clients from the members of the group
677
+ */
678
+ getClientIds(conversationId: ConversationId): Promise<ClientId[]>;
649
679
  /**
650
680
  * Allows {@link CoreCrypto} to act as a CSPRNG provider
651
681
  * @note The underlying CSPRNG algorithm is ChaCha20 and takes in account the external seed provider either at init time or provided with {@link CoreCrypto.reseedRng}
@@ -661,6 +691,82 @@ export declare class CoreCrypto {
661
691
  * @param seed - **exactly 32** bytes buffer seed
662
692
  */
663
693
  reseedRng(seed: Uint8Array): Promise<void>;
694
+ /**
695
+ * Initiailizes the proteus client
696
+ */
697
+ proteusInit(): Promise<void>;
698
+ /**
699
+ * Create a Proteus session using a prekey
700
+ *
701
+ * @param sessionId - ID of the Proteus session
702
+ * @param prekey - CBOR-encoded Proteus prekey of the other client
703
+ */
704
+ proteusSessionFromPrekey(sessionId: string, prekey: Uint8Array): Promise<void>;
705
+ /**
706
+ * Create a Proteus session from a handshake message
707
+ *
708
+ * @param sessionId - ID of the Proteus session
709
+ * @param envelope - CBOR-encoded Proteus message
710
+ */
711
+ proteusSessionFromMessage(sessionId: string, envelope: Uint8Array): Promise<void>;
712
+ /**
713
+ * Locally persists a session to the keystore
714
+ *
715
+ * @param sessionId - ID of the Proteus session
716
+ */
717
+ proteusSessionSave(sessionId: string): Promise<void>;
718
+ /**
719
+ * Deletes a session
720
+ * Note: this also deletes the persisted data within the keystore
721
+ *
722
+ * @param sessionId - ID of the Proteus session
723
+ */
724
+ proteusSessionDelete(sessionId: string): Promise<void>;
725
+ /**
726
+ * Decrypt an incoming message for an existing Proteus session
727
+ *
728
+ * @param sessionId - ID of the Proteus session
729
+ * @param ciphertext - CBOR encoded, encrypted proteus message
730
+ * @returns The decrypted payload contained within the message
731
+ */
732
+ proteusDecrypt(sessionId: string, ciphertext: Uint8Array): Promise<Uint8Array>;
733
+ /**
734
+ * Encrypt a message for a given Proteus session
735
+ *
736
+ * @param sessionId - ID of the Proteus session
737
+ * @param plaintext - payload to encrypt
738
+ * @returns The CBOR-serialized encrypted message
739
+ */
740
+ proteusEncrypt(sessionId: string, plaintext: Uint8Array): Promise<Uint8Array>;
741
+ /**
742
+ * Batch encryption for proteus messages
743
+ * This is used to minimize FFI roundtrips when used in the context of a multi-client session (i.e. conversation)
744
+ *
745
+ * @param sessions - List of Proteus session IDs to encrypt the message for
746
+ * @param plaintext - payload to encrypt
747
+ * @returns A map indexed by each session ID and the corresponding CBOR-serialized encrypted message for this session
748
+ */
749
+ proteusEncryptBatched(sessions: string[], plaintext: Uint8Array): Promise<Map<string, Uint8Array>>;
750
+ /**
751
+ * Creates a new prekey with the requested ID.
752
+ *
753
+ * @param prekeyId - ID of the PreKey to generate. This cannot be bigger than a u16
754
+ * @returns: A CBOR-serialized version of the PreKeyBundle corresponding to the newly generated and stored PreKey
755
+ */
756
+ proteusNewPrekey(prekeyId: number): Promise<Uint8Array>;
757
+ /**
758
+ * Proteus public key fingerprint
759
+ * It's basically the public key encoded as an hex string
760
+ *
761
+ * @returns Hex-encoded public key string
762
+ */
763
+ proteusFingerprint(): Promise<string>;
764
+ /**
765
+ * Imports all the data stored by Cryptobox into the CoreCrypto keystore
766
+ *
767
+ * @param storeName - The name of the IndexedDB store where the data is stored
768
+ */
769
+ proteusCryptoboxMigrate(storeName: string): Promise<void>;
664
770
  /**
665
771
  * Returns the current version of {@link CoreCrypto}
666
772
  *