Class KeyHandle
A key you can use and cannot read.
Why this is not a Key
Key is built around encoded bytes: the constructor requires them,
getEncoded() is final, and SecretKey is final on top of that.
Every one of those is correct for what that class is -- a value object wrapping key material --
and every one of them makes it impossible to represent a key whose material does not exist as
bytes the application can reach. A browser CryptoKey created with extractable: false is
exactly that key, and so is an Android keystore key and an iOS Secure Enclave key. Subclassing
would have produced a getEncoded() that either lies or throws, and code that takes a Key
would keep compiling while silently getting neither.
So this is a separate type with no byte accessor at all. There is no getEncoded, no
export, and no flag that turns one on. isExportable() reports whether the underlying
material could be exported by some other means -- it never provides the means.
What it does not protect against
A handle stops the key material being copied. It does not stop the key being used: while
the vault is unlocked, any code running in the application -- including script an XSS
injected into the page -- can call seal(byte[], AssociatedData) and open(byte[], AssociatedData) on a handle it can reach, exactly as
the application does. Non-extractability limits what an attacker can carry away, not what they
can do while they are there. destroy() and Vault.lock() cut that off for future calls and
cannot reach a plaintext already handed out.
Lifecycle
A handle obtained from a vault is invalidated when that vault locks. Calls afterwards fail
with VaultError.LOCKED rather than returning stale results, and an operation already in
flight when the lock happens does not deliver its result -- see Vault.lock().
-
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedSubclasses are created by the vault or by a port. -
Method Summary
Modifier and TypeMethodDescriptionabstract voiddestroy()Releases the handle and, where the material is held in this process, overwrites it.abstract StringThe algorithm this key is for, e.g.abstract StringgetKeyId()A stable identifier for this key, carried in the envelopes it seals so a reader holding several keys can pick the right one without trying each.abstract ProtectionReportWhat actually protects this key, as observed.abstract KeyUsage[]The operations this handle permits, fixed at creation.abstract intThe rotation counter.abstract booleanWhetherdestroy()has been called, or the owning vault has locked.abstract booleanWhether the key material could be exported through some other path.AsyncResource<byte[]> mac(byte[] data) A message authentication tag overdata, for a handle that permitsKeyUsage.MAC.abstract AsyncResource<byte[]> open(byte[] sealed, AssociatedData aad) Authenticated decryption of whatseal(byte[], AssociatedData)produced.booleanWhether this handle permits an operation.abstract AsyncResource<byte[]> seal(byte[] plaintext, AssociatedData aad) Authenticated encryption.verifyMac(byte[] data, byte[] tag) Verifies a tag from [#mac(byte[])], in constant time.
-
Constructor Details
-
KeyHandle
protected KeyHandle()Subclasses are created by the vault or by a port.
-
-
Method Details
-
getAlgorithm
The algorithm this key is for, e.g."AES-GCM". -
getKeyId
A stable identifier for this key, carried in the envelopes it seals so a reader holding several keys can pick the right one without trying each. -
getVersion
public abstract int getVersion()The rotation counter. Incremented by
; envelopes record the versioninvalid reference
Vault#rotateDataKey()that sealed them, so an old envelope can still be opened after a rotation and can be identified as needing a rewrite.
-
isExportable
public abstract boolean isExportable()Whether the key material could be exported through some other path.
falseis the interesting answer and means the platform holds the key in a form it will not hand back -- a non-extractableCryptoKey, a keystore alias, a Secure Enclave reference.truemeans the material exists as bytes somewhere in the process; the handle still will not give them to you, but it is not claiming the platform could not.This method never enables an export. There is no method on this class that does.
-
getUsages
The operations this handle permits, fixed at creation. -
permits
Whether this handle permits an operation. -
getProtection
What actually protects this key, as observed. SeeProtectionReport. -
seal
Authenticated encryption. The result is a
SecureEnvelope: the nonce, the key id and the version are managed here and are not the caller's to choose, because a reused nonce destroys AES-GCM and an API that let one be passed in would eventually see one.Parameters
-
plaintext: the bytes to protect -
aad: the binding the result may only be opened against, may be null
Returns
a resource completing with the sealed bytes, or erroring with a
VaultException -
-
open
Authenticated decryption of what
seal(byte[], AssociatedData)produced.On a tag mismatch the resource errors with
VaultError.AUTHENTICATION_FAILEDand no plaintext is delivered -- not a truncated one, not an unverified one. A caller that wants the bytes anyway cannot have them from here. -
mac
A message authentication tag over
data, for a handle that permitsKeyUsage.MAC.The default reports
VaultError.NOT_SUPPORTED; a handle whose platform provides HMAC overrides it. -
verifyMac
Verifies a tag from [#mac(byte[])], in constant time. -
destroy
public abstract void destroy()Releases the handle and, where the material is held in this process, overwrites it.
Best effort, and said so plainly: a managed runtime may have copied the buffer during a collection, the browser's heap is not ours to scrub, and a JIT may hold a register copy. What this does guarantee is that the handle stops working -- subsequent calls fail with
VaultError.LOCKED-- and that the application's own reference is cleared. -
isDestroyed
public abstract boolean isDestroyed()Whetherdestroy()has been called, or the owning vault has locked.
-