Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

envelock

Encrypted local storage for mobile apps. Envelope encryption with a hardware-gated key on one side and a recovery path on the other, so the everyday flow is a single biometric prompt and a lost device is not a lost vault.

  +-------------------+  +-------------------+  +-------------------+
  | Enclave secret    |  | Provider material |  | Recovery factor   |
  | envelock-owned    |  | host-supplied     |  | user-held         |
  | OS biometric gate |  | via callback      |  | recovery only     |
  +---------+---------+  +---------+---------+  +---------+---------+
            |                      |                      |
            +----------+-----------+                      |
                       v                                  v
              HKDF -> KEK_primary          [Argon2id +] HKDF -> KEK_recovery
                       |                                  |
                 Wrapped DEK (A)                    Wrapped DEK (B)
                       |                                  |
                       +-----------------+----------------+
                                         v
                                DEK -> encrypted records

Two independent wrappings of the same DEK. Either opens the vault, which is what keeps the everyday flow to one prompt while staying recoverable.

The cryptographic core is a single Rust implementation shared by every platform, so a vault written on iOS opens on Android byte-for-byte. This repository holds the platform wrappers, the generated bindings and the runnable examples; the core ships as a prebuilt binary.

Install

Current release: 0.2.0

Swift Package Manager

.package(url: "https://github.com/ShareRing/envelock.git", from: "0.2.0")

CocoaPods

EnvelockCore is distributed as a GitHub Release asset rather than through CocoaPods trunk, so the podspec is referenced by URL:

pod 'EnvelockCore', :podspec => 'https://github.com/ShareRing/envelock/releases/download/v0.2.0/EnvelockCore.podspec'

React Native and Flutter both depend on EnvelockCore, so that line belongs in the host app's Podfile for those integrations too.

Android

dependencies {
    implementation("network.sharering:envelock-android:0.2.0")
}

React Native

npm install @sharering/react-native-envelock

Then add the EnvelockCore Podfile line above and run pod install.

Flutter

Published to ShareRing's private OnePub registry:

dart pub global activate onepub
onepub auth
flutter pub add envelock

The one callback you write

envelock makes no network calls and holds no tokens. It calls you when it needs provider material, and the contract that matters is determinism: for a given key id, the bytes must be identical every single call. Break that and the vault stops opening.

Safe sources are a server-held per-user pepper, or WebAuthn PRF output for a fixed salt. What bricks user data: bearer or refresh tokens, anything with a timestamp or request id in it, device fingerprints, and anything derived from a PIN the user can change.

examples/reference-backend/ is a working endpoint that gets this right. It returns a key id alongside the material, so a pepper can be rotated without stranding existing vaults.

There is deliberately no token parameter and no endpoint option in the API. If fetching material needs a bearer token, use that token inside your own callback. Keeping it out of the signature makes "the token fetches the material, it is never the material" structural rather than a warning someone skips.

Start from examples/: one runnable demo per platform, each showing the library used directly and wrapped inside a host SDK.

The security floor

envelock always contributes its own enclave factor to KEK_primary, generated by envelock and never supplied or influenced by the caller. A provider callback can only ever add a factor, never lower the floor.

The type system enforces this rather than the docs. The enclave key store is a required constructor argument with no default, and the software stand-in exists only in test builds. Every released binary is checked for the absence of those symbols before it is published.

So the worst integration anyone can write, a callback returning 32 constant bytes, still leaves you with a device-bound key behind an OS biometric gate. Never plaintext-equivalent.

Layout

Path What
platform/ios/ Secure Enclave shim and the generated Swift bindings
platform/android/ Keystore shim and the generated Kotlin bindings
bindings/react-native/ Native module, TypeScript, JSI buffer bridge
bindings/flutter/ Pigeon + Dart
examples/ Runnable demos, one per platform

License

Apache-2.0. See LICENSE.

About

Encrypted local storage for mobile apps

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages