Crate core_crypto

Source
Expand description

Core Crypto is a wrapper on top of OpenMLS aimed to provide an ergonomic API for usage in web through Web Assembly and in mobile devices through FFI.

The goal is provide a easier and less verbose API to create, manage and interact with MLS groups.

§Wire CoreCrypto

This repository is part of the source code of Wire. You can find more information at wire.com or by contacting opensource@wire.com.

You can find the published source code at github.com/wireapp/wire.

For licensing information, see the attached LICENSE file and the list of third-party licenses at wire.com/legal/licenses/.

No license is granted to the Wire trademark and its associated logos, all of which will continue to be owned exclusively by Wire Swiss GmbH. Any use of the Wire trademark and/or its associated logos is expressly prohibited without the express prior written consent of Wire Swiss GmbH.

§Parts

  • CoreCrypto: Abstracts MLS & Proteus in a unified API
  • CoreCryptoFFI: FFI bindings for iOS, Android and WASM
  • Keystore: Encrypted Keystore powered by SQLCipher on all platforms except WASM. WASM uses an IndexedDB-backed, encrypted store with AES256-GCM
  • MlsProvider: RustCrypto + Keystore MLS provider

See ARCHITECTURE.md

§Usage

§API Docs

§Building

§General Requirements

If you’re using macOS, you’ll also need to install GNU sed:

brew install gnu-sed make

and add aliases to your shell configuration file: alias sed=gsed, aliase make=gmake (e.g. to ~/.zshenv if you’re using zsh).

§Pre-commit

§Android

Install Android SDK and Build-Tools for API level 30+

If you are building on macOS you’ll need to setup $ANDROID_SDK_ROOT path variable manually:

export ANDROID_SDK_ROOT=~/Android/Sdk

Install the Android NDK

Install android rust targets:

rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi

Build:

make android

§iOS

Install Xcode & its command-line tools: https://developer.apple.com/xcode/.

Install iOS rust targets:

rustup target add aarch64-apple-ios aarch64-apple-ios-sim

Build:

make ios
# Additionally, if you want to export a .XCFramework:
make ios-create-xcframework

§MacOS

Install macOS rust targets:

rustup target add aarch64-apple-darwin

§Linux

If cross-compiling from macOS, you’ll need to install https://github.com/messense/homebrew-macos-cross-toolchains.

Install Linux targets:

rustup target add x86_64-unknown-linux-gnu

§WASM

Make sure you have all prerequisites:

  • Install wasm-pack
  • Install the wasm32-unknown-unknown toolchain: rustup target add wasm32-unknown-unknown
  • Install node.js (recommended way is via Volta)
  • Install Bun (follow the instructions on Bun’s website)

Build:

make ts

§Bindings

Build bindings for Android, JVM, iOS and WASM

# builds bindings and targets for the JVM (macOS / Linux)
make jvm

# builds bindings and targets for Android
make android

# builds iOS framework
make ios-create-xcframework

# builds wasm binary & TS bindings
make ts

§Testing

§General testing

# Install cargo-nextest if you haven't done so, it yields some substantial speedup
cargo install cargo-nextest
cargo nextest run

§Run core crypto internal tests on WASM target

If you haven’t already, install the target and wasm-pack:

rustup target add wasm32-unknown-unknown
cargo install wasm-pack

If you want to test for chrome, get chromedriver or the webdriver for the browser you want to test for, respectively.

Then, to run tests for a crate in the workspace do

wasm-pack test --headless --chrome ./<crate-folder-to-test>
§Addendum: testing all ciphersuites

This takes quite a while.

cargo nextest run --features test-all-cipher

§Platform-specific tests for Kotlin/JVM

make jvm-test

§Platform-specific tests for Android

make android-test

§Swift/iOS

No E2E testing is available as of now on Swift.

§Platform-specific tests for WASM/Web

make ts-test

Note the CC_TEST_LOG_LEVEL environment variable. At 1 it emits browser console logs; at 2 it also emits CoreCrypto logs.

§Benchmarks

There are benches implemented in crypto/benches for several operations on mls groups with varying sizes or proteus. Parameters like minimum or maximum group sizes and step sizes are defined in crypto/benches/utils/mod.rs.

§Executing Benches

To execute the benches, e.g. for creating commits, run

cargo bench --bench=commit -- --quick

where commit is the name of the bench specified in crypto/Cargo.toml, and the corresponding file in crypto/benches. In case you’re interested in higher accuracy, and willing to trade it for execution speed, omit the --quick flag. If you need reporting plots, remove the .without_plots() call in crypto/benches/utils/mod.rs. The reports generated by criterion will be located in target/criterion.

§Git workflow

  • The main branch is used as the everyday development branch.
  • No merge commits. Always rebase on top of main.
  • Release branches are named release/<series>, e.g. release/1.x, release/2.x.
  • Release branches contain fixes relevant to their specific release series and are never merged to main.
  • Release branches always branch off their first major release tag. For example, the output of git merge-base main release/2.x must be a commit pointed to by tag v2.0.0.
  • Release branches are created lazily, that is, only when the first fix needs to be applied and released for a specific release series.
  • Use conventional commits – those are picked up by the changelog generator.
  • If there is a JIRA ticket related to the change, you should mention it in either the PR title or the commit(s), with the following format: [TICKET_ID].
  • Sign your commits and tags.
  • Remove branches from the remote once you don’t need them anymore.

§Publishing

§Versioning

The versioning scheme used is SemVer AKA Semantic Versioning.

§Making a new release

  1. Make a branch based on main to prepare for release (git checkout -b prepare-release/X.Y.Z)
  2. Run sh scripts/update-versions.sh X.Y.Z to update the versions of
    • all workspace member crates
    • package.json
    • crypto-ffi/bindings/gradle.properties Make sure the result of the script run is correct.
  3. Generate the relevant changelog section:
    git cliff --bump --unreleased
    and add it to the top of CHANGELOG.md. Make sure the version number generated by git cliff matches the release version.
  4. If there are any release highlights, add them as the first subsection below release title:
    ## v1.0.2 - 2024-08-16
    
    ### Highlights
    
    - foo
    - bar
    - baz
  5. In index.md, copy the commented-out table row from the bottom of the file to the appropriate place in the table, ordering by version number, descending. Search and replace the first 5 occurrences of x.x.x with X.Y.Z.
  6. Make sure the changes look reasonable and complete; you can use the previous release as a reference
  7. Push your prepare-release/X.Y.Z branch and create a PR for it
  8. Get it reviewed, then merge it into main and remove the prepare-release/X.Y.Z branch from the remote
  9. Now, pull your local main: git checkout main && git pull
  10. Create the release tag: git tag -s vX.Y.Z
  11. Push the new tag: git push origin tag vX.Y.Z
  12. Create a new release on github, copying the relevant section from CHANGELOG.md
  13. Voilà!
§Consider when making a release from a release branch
  1. Isolate the changes to index.md and CHANGELOG.md from the release commit itself
  2. After the release is finished, cherry-pick the changes to index.md and CHANGELOG.md and get them into main
  3. For release series 4.x and newer, docs upload happens automatically. If you released from the series 3.x or older, you need to trigger docs upload manually:
    1. On GitHub, go to the docs workflow
    2. Click the Run workflow button
    3. In the Use workflow from dropdown, choose release/5.x, in Tag to checkout provide your release tag

§Publishing Android / JVM bindings

Publishing Android / JVM bindings happens automatically by a github workflow when a release tag is pushed.

If you would like to publish the bindings to a local Maven cache, run:

cd crypto-ffi/bindings
./gradlew :jvm:publishToMavenLocal
./gradlew :android:publishToMavenLocal

§Publishing JS / WASM bindings

Publishing JS / WASM bindings happens automatically by a github workflow when a release tag is pushed.

If you would like to publish to @wireapp/core-crypto manually, log into NPM and just run bun publish.

Re-exports§

pub use crate::e2e_identity::E2eiEnrollment;
pub use crate::e2e_identity::types::E2eiAcmeChallenge;
pub use crate::e2e_identity::types::E2eiAcmeDirectory;
pub use crate::e2e_identity::types::E2eiNewAcmeAuthz;
pub use crate::e2e_identity::types::E2eiNewAcmeOrder;
pub use crate::mls::conversation::ConversationId;
pub use crate::mls::conversation::MlsConversation;

Modules§

e2e_identity
re-export rusty-jwt-tools API
mls
MLS Abstraction
proteus
Proteus Abstraction
transaction_context
This module contains the primitives to enable transactional support on a higher level within the Session. All mutating operations need to be done through a TransactionContext.

Structs§

BuildMetadata
Metadata describing the conditions of the build of this software.
CertificateBundle
Represents a x509 certificate chain supplied by the client It can fetch it after an end-to-end identity process where it can get back a certificate from the Authentication Service
ClientId
A Client identifier
CoreCrypto
Wrapper superstruct for both mls::session::Session and proteus::ProteusCentral
Credential
Credential.
Database
DatabaseKey
The key used to encrypt the database.
EntropySeed
Wrapped 32-byte entropy seed with bounds check
GroupEpoch
Group epoch. Internally this is stored as a u64. The group epoch is incremented with every valid Commit that is merged into the group state.
HistorySecret
A HistorySecret encodes sufficient client state that it can be used to instantiate an ephemeral client.
KeyPackage
The key package struct.
KeyPackageIn
The key package struct.
KeystoreError
A key store operation failed
MlsBufferedConversationDecryptMessage
Type safe recursion of MlsConversationDecryptMessage
MlsCiphersuite
A wrapper for the OpenMLS Ciphersuite, so that we are able to provide a default value.
MlsCommitBundle
Returned when a commit is created
MlsConversationConfiguration
The configuration parameters for a group/conversation
MlsConversationDecryptMessage
Represents the potential items a consumer might require after passing us an encrypted message we have decrypted for him
MlsCryptoProvider
MlsCustomConfiguration
The configuration parameters for a group/conversation which are not handled natively by openmls
MlsGroup
A MlsGroup represents an MLS group with a high-level API. The API exposes high level functions to manage a group by adding/removing members, get the current member list, etc.
MlsGroupConfig
Specifies the configuration parameters for a MlsGroup. Refer to the User Manual for more information about the different configuration values.
MlsGroupInfoBundle
A [GroupInfo] with metadata
MlsMessageIn
Before use with the MlsGroup API, the message has to be unpacked via extract to yield its [MlsMessageInBody].
MlsProposalBundle
Returned when a Proposal is created. Helps roll backing a local proposal
MlsProposalRef
Abstraction over a [openmls::prelude::hash_ref::ProposalRef] to deal with conversions
MlsTransportData
An entity / data which has been packaged by the application to be encrypted and transmitted in an application message.
Session
A MLS Session enables a user device to communicate via the MLS protocol.
SessionConfig
Configuration parameters for Session
UserId
Unique identifier of a User (human person holding some devices). This contradicts the initial design requirements of this project since it was supposed to be agnostic from Wire. End-to-end Identity re-shuffled that… But we still want to keep this isolated from the rest of the crate that’s why this should remain here and be used cautiously, having the context quoted above in mind. For example in wireapp://LcksJb74Tm6N12cDjFy7lQ!8e6424430d3b28be@wire.com the UserId is LcksJb74Tm6N12cDjFy7lQ
ValidatedSessionConfig
Validated configuration parameters for Session.
VerifiableGroupInfo
A type that represents a group info of which the signature has not been verified. It implements the [Verifiable] trait and can be turned into a group info by calling verify(...) with the signature key of the Credential. When receiving a serialized group info, it can only be deserialized into a VerifiableGroupInfo, which can then be turned into a group info as described above.
WelcomeBundle
Contains everything client needs to know after decrypting an (encrypted) Welcome message
WireIdentity
Represents the identity claims identifying a client Those claims are verifiable by any member in the group
X509Identity
Represents the parts of WireIdentity that are specific to a X509 certificate (and not a Basic one).

Enums§

CiphersuiteName
MLS ciphersuites.
ClientIdentifier
Used by consumers to initializes a MLS client. Encompasses all the client types available. Could be enriched later with Verifiable Presentations.
ConnectionType
Where to open a connection
DeviceStatus
Indicates the standalone status of a device Credential in a MLS group at a moment T. This does not represent the states where a device is not using MLS or is not using end-to-end identity
E2eiConversationState
Indicates the state of a Conversation regarding end-to-end identity.
Error
Errors produced by the root module group
GroupInfoPayload
Represents the byte array in MlsGroupInfoBundle
LeafError
These errors can be raised from several different modules, so we centralize the definitions here to ease error-handling.
MlsCredentialType
Lists all the supported Credential types. Could list in the future some types not supported by openmls such as Verifiable Presentation
MlsErrorKind
Openmls produces these kinds of error
MlsGroupInfoEncryptionType
GroupInfoEncryptionType
MlsProposal
Internal representation of proposal to ease further additions
MlsRatchetTreeType
RatchetTreeType
MlsTransportResponse
Response from the delivery service
MlsWirePolicy
Wrapper over WireFormatPolicy
Node
Container enum for leaf and parent nodes.
ProteusErrorKind
Proteus produces these kinds of error
RecursiveError
These errors wrap each of the module-specific errors in CoreCrypto.

Constants§

BUILD_METADATA
Metadata describing the conditions of the build of this software.
HISTORY_CLIENT_ID_PREFIX
We always instantiate history clients with this prefix in their client id, so we can use prefix testing to determine with some accuracy whether or not something is a history client.
INITIAL_KEYING_MATERIAL_COUNT
Default number of KeyPackages a client generates the first time it’s created

Traits§

EpochObserver
An EpochObserver is notified whenever a conversation’s epoch changes.
HistoryObserver
The HistoryObserver will be called when updating the history client in a conversation
InnermostErrorMessage
Produce the error message from the innermost wrapped error.
MlsTransport
Client callbacks to allow communication with the delivery service. There are two different endpoints, one for messages and one for commit bundles.
ToRecursiveError
Like Into, but different, because we don’t actually want to implement Into for our subordinate error types.

Type Aliases§

KeyPackageRef
A reference to a key package. This value uniquely identifies a key package.
MlsError
A MLS operation failed, but we captured some context about how it did so
ProteusError
A Proteus operation failed, but we captured some context about how it did so
RawEntropySeed
32-byte raw entropy seed
Result
A module-specific Result type with a default error variant.