Class SecureStorageDeviceProtection
The DeviceProtection every port gets when it does not supply one of its own: a random
wrapping key in SecureStorage, and AES-GCM performed in shared code.
This is the right implementation wherever SecureStorage is the operating system's secret
store -- the iOS keychain, the Android keystore, the desktop credential store. The wrapping
key is bytes, and it is bytes in the one place on the device that is built to hold bytes
nobody else should reach.
It is the wrong implementation in a browser, where SecureStorage is ordinary
origin-private storage: the wrapping key would sit beside the ciphertext it protects, which is
no protection at all. The JavaScript port therefore overrides
CodenameOneImplementation.getDeviceProtection() with one built on a
non-extractable CryptoKey, and this class never runs there.
Racing callers
Key creation goes through SecureStorage.setIfAbsent(String, String), which returns what the
store ended up holding rather than what this call wrote. Two processes that both find nothing
therefore agree on one key instead of each overwriting the other -- which matters more here
than almost anywhere, because the loser's key is what a device's remembered vault was wrapped
under.
-
Field Summary
Fields inherited from class DeviceProtection
KEY_ABSENT, KEY_PRESENT, KEY_UNKNOWN -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionRemoves the device key, which is what "forget this device" does.Creates the device key if there is none, and converges when two callers race.intWhether a device key exists for this id.What this device protection actually provides, as observed rather than as advertised.protected SecureStoragestorage()The store backing this.AsyncResource<byte[]> Decrypts whatDeviceProtection.wrap(String, byte[], byte[])produced.AsyncResource<byte[]> Encrypts under the device key.Methods inherited from class DeviceProtection
requiresUserVerification, setDeviceBoundRequired, userVerifying
-
Constructor Details
-
SecureStorageDeviceProtection
public SecureStorageDeviceProtection()
-
-
Method Details
-
storage
The store backing this. Overridable so a port can supply a store other than the oneSecureStorage.getInstance()returns, which the simulator's test harness uses. -
protection
Description copied from class:DeviceProtectionWhat this device protection actually provides, as observed rather than as advertised.
A port that has not yet tried an operation may only report what it can verify; several answers are legitimately
ProtectionReport.UNKNOWN-- no browser can say whether a key is hardware backed, and reportingNOthere would understate an authenticator that uses a secure element.- Specified by:
protectionin classDeviceProtection
-
keyState
Description copied from class:DeviceProtectionWhether a device key exists for this id.
Parameters
keyId: the vault's device key id
Returns
DeviceProtection.KEY_PRESENT,DeviceProtection.KEY_ABSENTorDeviceProtection.KEY_UNKNOWN- Specified by:
keyStatein classDeviceProtection
-
ensureKey
Description copied from class:DeviceProtectionCreates the device key if there is none, and converges when two callers race.
Parameters
keyId: the vault's device key id
Returns
a resource completing with
truewhen a key is in place -- whether this call created it or found another one already there -- and erroring with aVaultExceptionwhen no key could be established- Specified by:
ensureKeyin classDeviceProtection
-
wrap
Description copied from class:DeviceProtectionEncrypts under the device key.
Parameters
-
keyId: the vault's device key id -
plaintext: what to protect, normally a vault's 32 byte data key -
aad: associated data the result is bound to; the same bytes must be supplied toDeviceProtection.unwrap(String, byte[], byte[])
Returns
a resource completing with the wrapped bytes. The format is the port's own and is never interpreted by shared code, but it must be authenticated
- Specified by:
wrapin classDeviceProtection
-
-
unwrap
Description copied from class:DeviceProtectionDecrypts what
DeviceProtection.wrap(String, byte[], byte[])produced.A failure to authenticate must arrive as
VaultError.AUTHENTICATION_FAILED, a missing key asVaultError.KEY_MISSING, and a store that could not be read asVaultError.TEMPORARILY_UNREADABLE. Collapsing the last two is how a vault regenerates a key and orphans its data.- Specified by:
unwrapin classDeviceProtection
-
deleteKey
Description copied from class:DeviceProtectionRemoves the device key, which is what "forget this device" does.
Everything wrapped under it becomes unopenable on this device. That is the intent; it is not revocation, because a copy taken while the key existed is beyond reach.
- Specified by:
deleteKeyin classDeviceProtection
-