Encrypted video creates an awkward engineering problem. A player expects seekable media bytes, but an encrypted vault stores ciphertext the decoder cannot understand. The simplest workaround is to decrypt the complete movie to a temporary file and delete it later. Startup time and temporary-disk exposure then grow with the video.
A better Android path is possible when the file is divided into independently authenticated chunks. The vault maps each player request to its encrypted chunks, verifies and decrypts only those chunks, and returns the requested plaintext from memory.
Quick answer
Yes—but “without full decryption” does not mean “without any decryption.” Krypt's current Android player can play and seek within newly imported chunked videos without first creating a plaintext copy of the entire video, subject to the media format and current bridge limits described below. Krypt stores those files with a 48-byte format header, a 24-byte base nonce, and independently authenticated XChaCha20-Poly1305 chunks. The default plaintext chunk size is 1 MiB.
When Android Media3 asks for a byte range, Krypt determines which chunks overlap that range, verifies each chunk's 16-byte authentication tag, decrypts those chunks, and returns only the relevant bytes. An eight-chunk least-recently-used cache avoids repeatedly decrypting nearby data. This native random-access path currently applies only on Android and only to current chunked files. iOS and macOS use a temporary-file preview path, and legacy or unsupported files may require an explicit export.
Why ordinary whole-file encryption fights video playback
A video container is not consumed strictly from byte zero to the end. A player may inspect headers, locate track metadata, buffer future samples, revisit an earlier range, or jump to an index after the user drags the timeline. Some MP4 files place important metadata near the end. Different containers and codecs have different seeking rules. A vault that encrypts one entire file as a single authenticated message normally must verify that message before trusting any of its plaintext.
Decrypting the complete object recreates the ordinary file the player expects, but introduces costs:
- Startup latency: playback may wait while gigabytes are read, authenticated, decrypted, and written.
- Temporary storage: the device needs enough free space for a plaintext copy in addition to the ciphertext.
- Cleanup obligations: crashes, filesystems, and flash-storage remapping complicate deletion.
- Unnecessary work: watching the first two minutes should not require decrypting a two-hour recording.
Chunking changes the unit of authentication from the entire object to a bounded section of it. That enables random reads while preserving a rule that matters: no chunk is released to the media pipeline unless its authentication check succeeds.
Inside Krypt's chunked video format
Current Krypt video imports use a compact binary header followed by authenticated ciphertext chunks. The 48-byte header records the format magic and version, flags, algorithm identifier, configured chunk size, 24-byte base nonce, original plaintext length, and chunk count. The default chunk size is 1,048,576 bytes, or 1 MiB. Every encrypted chunk adds a 16-byte Poly1305 authentication tag.
Krypt derives each chunk nonce by XORing the chunk index into the last eight bytes of a copied 24-byte base nonce. Chunks therefore do not reuse one nonce under the file key. The reader validates the header's version, algorithm, size limits, alignment, and declared chunk count before opening a stream.
XChaCha20-Poly1305 is authenticated encryption with associated data, or AEAD: it provides confidentiality and a tag that detects a modified ciphertext under the expected key and nonce. The public libsodium construction documentation describes XChaCha20-Poly1305's 192-bit nonce and verify-before-decrypt behavior. Krypt's on-disk design is its own indexed per-chunk format; this citation explains the construction, not a claim that Krypt uses libsodium's separate secretstream file format.
How one byte-range request becomes authenticated plaintext
Suppose the player requests bytes starting halfway through chunk 20 and ending in chunk 22. Krypt performs the following work:
- Clamp the requested end to the declared plaintext size.
- Divide the start and end positions by the stored chunk size to identify chunks 20 through 22.
- Calculate each ciphertext offset from the 48-byte header, the fixed chunk size, and the 16-byte tag added to each preceding chunk.
- Read each required ciphertext-and-tag record from the encrypted file.
- Derive the indexed nonce, authenticate and decrypt the chunk, and reject the read if verification fails.
- Copy only the requested slice of the first and last plaintext chunks into the response.
The decryption service caches up to eight plaintext chunks for that open stream. Each cache hit is promoted to most recently used; adding a ninth distinct chunk evicts the oldest. With the default format, the cache can hold about 8 MiB of plaintext plus object overhead. It is an in-memory playback optimization, not a decrypted copy written alongside the vault file.
How Android Media3 reaches the encrypted reader
Android's Media3 player is built to accept custom data-loading components. Google's Media3 customization guide explicitly supports injecting a custom DataSource.Factory into a ProgressiveMediaSource. Krypt uses that seam: Media3 sees a seekable logical media resource, while Krypt's custom data source obtains authenticated ranges from the encrypted vault.
A Media3 DataSpec defines a region using a byte position and either a length or an open-ended request. Krypt opens its logical stream at that position. For an open-ended request it reports the clamped bytes remaining; when Media3 supplies a fixed length it returns that requested length. Player reads are translated into upstream fetches that target 1 MiB to 4 MiB, although the final fetch can be smaller than 1 MiB. The range reader still authenticates the exact 1 MiB chunks needed underneath.
Seeking works through the same contract. When Media3 reopens at a new byte position, Krypt discards the old prefetch buffer, begins at the new offset, and decrypts the overlapping chunks. The official progressive-media guide also makes an important limitation clear: seek support depends on the media container and its indexes. A random-access data source cannot make an inherently unseekable or unsupported container seekable.
Authentication is more important than selective decryption
Encryption alone would not be enough. If altered ciphertext reached a parser, corruption could become a crash, misleading output, or an attack surface in a complex media decoder. Each Krypt chunk is authenticated before its plaintext is returned. A truncated chunk, bad tag, invalid header, unexpected end of file, or out-of-range request fails instead of silently producing bytes.
This does not make an unlocked device invulnerable. Selected plaintext exists briefly in process memory so Media3 and the decoder can use it. Malware controlling the device may attack data after decryption. Krypt applies Android's secure-window flag to the native player, but no app can protect data after full endpoint compromise.
Current platform and format limits
The precise boundaries matter more than a broad “encrypted streaming” label:
- Android only: native random-access encrypted video playback is currently implemented on Android.
- Current chunked files only: legacy, non-chunked videos are not accepted by the Android stream service. New video imports use the chunked format.
- Current 2 GiB bridge limit: Android tracks player offsets as 64-bit values but currently casts the requested offset to a signed 32-bit integer before calling the Dart range reader. A request at or beyond 2,147,483,648 bytes can wrap negative and fail, so very large videos are not reliably supported across their complete byte range.
- Supported media only: Android Media3 still needs a supported container, extractor, codec, and device decoder. A valid encrypted file can still be unplayable as media.
- Apple temporary path: on iOS and macOS, Krypt decrypts the selected current video to a temporary file for the platform player. When it is released or the preview closes, Krypt attempts secure overwrite and deletion, retries cleanup, and can queue a remaining path for background deletion.
- Fallback is explicit: when native preview is unavailable, Krypt exposes Save As or Export/Share actions. Export intentionally creates a user-accessible plaintext copy, so its destination inherits the security of the filesystem and apps that receive it.
Secure deletion on flash storage is best effort because filesystems, snapshots, and storage controllers may retain old physical blocks outside an app's control. Cleanup reduces exposure; it is not a mathematical erasure guarantee.
What this feature is not
Krypt's Android path is local encrypted-file playback. It is not a video hosting service, an HTTP range server, adaptive network streaming, or a digital-rights-management system. It does not implement HLS or DASH license exchange, Widevine policy enforcement, expiring viewing rights, or remote bandwidth adaptation. The ciphertext is already stored in the user's vault, and the app is satisfying local byte-range requests after the vault has been unlocked.
It is also not “zero plaintext.” Decoders require plaintext media bytes. The meaningful security improvement is narrower: avoid materializing the entire supported video as a plaintext file before playback, authenticate each requested chunk, keep the working set bounded, and close the encrypted-file session when playback ends.
Krypt's answer: local encrypted media with bounded exposure
Krypt is a zero-knowledge password manager and secure vault for more than passwords. Its encrypted media features keep original video data in vault storage and, on supported Android files, expose only authenticated ranges to the player rather than writing a full temporary playback copy.
The design answers a practical question: how can a private video remain useful without treating “decrypt everything first” as the only playback architecture? Krypt uses indexed authenticated chunks, a range reader, a bounded plaintext cache, and Android Media3's custom data-source contract. It then states the exceptions plainly: Apple previews use temporary files today, old formats do not gain random access retroactively, and exports leave the vault's protection.
Encrypted-video safety checklist
- Import the original into Krypt and confirm playback before deleting the source.
- Use a current Krypt build so new videos are stored in the chunked format.
- Keep the vault locked when it is not in use and use an independent vault PIN.
- On Android, prefer in-app playback over Export when the format and codec are supported.
- On iOS or macOS, allow preview cleanup to finish before force-quitting the app.
- Treat any exported copy as ordinary plaintext and remove it from Downloads, shared folders, cloud sync, and trash when no longer needed.
- Maintain an encrypted backup and matching Recovery Kit; playback convenience is not a backup strategy.
- Remember the endpoint limit: do not open highly sensitive media on a device you believe is compromised.
FAQ
Does Krypt decrypt any video data during playback?
Yes. A player cannot decode ciphertext. On Android, Krypt decrypts and authenticates only the chunks needed for the requested byte range, returns the relevant plaintext bytes in memory, and keeps up to eight recently used plaintext chunks in a per-stream cache. It does not decrypt the entire supported chunked video to a playable file first.
Can Krypt seek inside an encrypted video on Android?
Yes, when the current chunked file uses a container and codec that Android Media3 can seek and decode. Media3 opens a byte range at the requested position, and Krypt maps that position to the required authenticated chunks. Container limitations, unsupported codecs, damaged files, or legacy non-chunked storage can still prevent native seeking or playback. Krypt's current bridge also cannot reliably read ranges at or beyond 2 GiB.
Does Krypt use the same encrypted-video playback path on iOS and macOS?
No. Native random-access decryption is currently Android-only. On iOS and macOS, Krypt decrypts the selected current video to a temporary file for the platform player, then attempts secure overwrite and deletion when that resource is released or the preview closes, with queued cleanup retries if immediate deletion fails.
Technical references
Google's Media3 customization documentation describes custom DataSource implementations and their injection into progressive media sources. The DataSpec API reference defines the position-and-length region contract used for random reads, while the progressive media guide documents supported containers and format-specific seek limits.
The libsodium XChaCha20-Poly1305 construction reference explains the 192-bit nonce, authentication tag, and verification behavior of the AEAD construction. Krypt's format and source code remain the authority for its 48-byte header, 1 MiB default chunks, indexed nonce derivation, 16-byte per-chunk tags, and eight-chunk cache.
Store sensitive video, photos, files, passwords, and recovery material in one local-first encrypted vault—with range-based Android video playback for current chunked files.