Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asynchronous interfaces #675

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
43 changes: 43 additions & 0 deletions docs/Migration-from-1.9-to-1.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:

- PowerAuth mobile SDK no longer supports activation by the recovery code.
- New `PowerAuthBiometricConfiguration` class that simplifies biometric configuration of `PowerAuthSDK` class.
- PowerAuth mobile SDK now ensures sensitive keys are not retained in memory.

### Compatibility with PowerAuth Server

- This release is fully compatible with PowerAuth Server version `1.9.0` and newer.

## Android

Notable changes on Android:

- New `PowerAuthBiometricPrompt` class simplifies biometric key setup and authentication.
- Added the `SecureData` class to `io.getlime.security.powerauth.core` package to enhance in-memory management of sensitive data.

### API changes

- The following methods in `PowerAuthSDK` class are deprecated:
- `changePasswordUnsafe()` - use asynchronous `changePassword()` as a replacement.
- `persistActivationWithAuthentication()` - use asynchronous variant with `IPersistActivationListener` as a callback parameter.
- `persistActivationWithPassword()` - use asynchronous variant with `IPersistActivationListener` as a callback parameter.
- `persistActivation(..., IPersistActivationWithBiometricsListener)` - use asynchronous method with `IPersistActivationListener` as a callback parameter.

- The following methods in `PowerAuthKeychainConfiguration` are now deprecated:
- `isLinkBiometricItemsToCurrentSet()` - use `PowerAuthBiometricConfiguration.isInvalidateBiometricFactorAfterChange()` instead.
Expand All @@ -26,6 +35,9 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:
- `Builder.authenticateOnBiometricKeySetup()` - use equal method in `PowerAuthBiometricConfiguration.Builder` instead.
- `Builder.enableFallbackToSharedBiometryKey()` - use equal method in `PowerAuthBiometricConfiguration.Builder` instead.

- The following classes and interfaces are now deprecated:
- `IPersistActivationWithBiometricsListener` - use `IPersistActivationListener` instead.

- Due to removed support of recovery codes, the following classes and methods are no longer available:
- Methods removed in `PowerAuthSDK`:
- `createRecoveryActivation()`
Expand All @@ -46,6 +58,21 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:
- `IConfirmRecoveryCodeListener`
- `RecoveryData`

- The following functions now takes or returns `SecureData` instead of `byte[]`:
- `PowerAuthSDK.persistActivationWithPassword()`
- `PowerAuthSDK.addBiometryFactor()`
- `PowerAuthSDK.setExternalEncryptionKey()`
- `PowerAuthSDK.addExternalEncryptionKey()`
- `PowerAuthConfiguration.getExternalEncryptionKey()`
- `PowerAuthConfiguration.Builder.externalEncryptionKey()`
- `PowerAuthAuthentication.getBiometryFactorRelatedKey()`
- `PowerAuthAuthentication.getOverriddenPossessionKey()`
- All static functions in `PowerAuthAuthentication` that takes custom possession or biometry key in parameter.
- `IFetchEncryptionKeyListener.onFetchEncryptionKeySucceed()`
- `CryptoUtils.ecdhComputeSharedSecret()`
- `BiometricKeyData.getDerivedData()`
- `BiometricKeyData.getDataToSave()`

- Removed all interfaces deprecated in release `1.9.x`

### Other changes
Expand All @@ -54,10 +81,16 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:

## iOS & tvOS

Notable changes on iOS:

- Added the `PowerAuthCoreData` object to `PowerAuthCore` module to enhance in-memory management of sensitive data.

### API changes

- The following methods in `PowerAuthSDK` class are deprecated:
- `unsafeChangePassword(from:to:)` - use asynchronous `changePassword(from:to:callback:)` as a replacement.
- `persistActivation(with:)` - use asynchronous `persistActivation(with:callback:)` as a replacement.
- `persistActivation(withPassword:)` - use asynchronous `persistActivation(withPassword:callback:)` as a replacement.
- Constructor `PowerAuthSDK(configuration:keychainConfiguration:clientConfiguration:)` - use methods with `PowerAuthBiometricConfiguration` parameter instead.

- All static methods for accessing a various shared instances are now deprecated:
Expand Down Expand Up @@ -86,6 +119,16 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:
- removed property `PowerAuthActivationResult.activationRecovery`
- removed constructor `PowerAuthActivation(recoveryCode:recoveryPuk:name:)`

- The following functions or properties now takes or returns `PowerAuthCoreData` instead of `Data`:
- `PowerAuthSDK.setExternalEncryptionKey()`
- `PowerAuthSDK.addExternalEncryptionKey()`
- `PowerAuthSDK.fetchEncryptionKey()`
- `PowerAuthConfiguration.externalEncryptionKey`
- All static functions in `PowerAuthAuthentication` that takes custom possession or biometry key in parameter.
- `PowerAuthAuthentication.overridenPossessionKey` property is now `customPossessionKey`
- `PowerAuthAuthentication.overridenBiometryKey` property is now `customBiometryKey`
- `PowerAuthCoreCryptoUtils.ecdhComputeSharedSecret()`

- Removed all interfaces deprecated in release `1.9.x`

### Other changes
Expand Down
182 changes: 89 additions & 93 deletions docs/PowerAuth-SDK-for-Android.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [Verify Server-Signed Data](#verify-server-signed-data)
- [Password Change](#password-change)
- [Working with passwords securely](#working-with-passwords-securely)
- [Working with sensitive data](#working-with-sensitive-data)
- [Biometric Authentication Setup](#biometric-authentication-setup)
- [Device Activation Removal](#activation-removal)
- [End-To-End Encryption](#end-to-end-encryption)
Expand Down Expand Up @@ -552,83 +553,68 @@ try {

After you create an activation using one of the methods mentioned above, you need to persist the activation - to use provided user credentials to store the activation data on the device. Use the following code to do this.

<!-- begin codetabs Kotlin Java -->
```kotlin
// Persist activation using given PIN
val result = powerAuthSDK.persistActivationWithPassword(context, pin)
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
```
```java
// Persist activation using given PIN
int result = powerAuthSDK.persistActivationWithPassword(context, pin);
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
```
<!-- end -->

This code has created activation with two factors: possession (key stored using a key derived from a device fingerprint) and knowledge (password, in our case, a simple PIN code). If you would like to enable biometric authentication support at this moment, use the following code instead of the one above:

<!-- begin codetabs Kotlin Java -->
```kotlin
// Persist activation using given PIN and ad-hoc generated biometric related key
powerAuthSDK.persistActivation(context, fragment, "Enable Biometric Authentication", "To enable biometric authentication, use the biometric sensor on your device.", pin, object: IPersistActivationWithBiometricsListener {
override fun onBiometricDialogCancelled() {
// Biometric enrolment cancelled by user
val authentication = PowerAuthAuthentication.persistWithPassword(pin)
val cancelable = powerAuthSDK.persistActivationWithAuthentication(context, authentication, object: IPersistActivationListener {
override fun onPersistActivationSucceeded() {
// Success
}

override fun onBiometricDialogSuccess() {
// success, activation has been persisted
override fun onPersistActivationFailed(error: PowerAuthErrorException) {
// Failure
}

override fun onBiometricDialogFailed(error: PowerAuthErrorException) {
// failure, typically as a result of API misuse, or a biometric authentication failure
override fun onPersistActivationCancelled(userCancel: Boolean) {
if (userCancel) {
// user cancelled the biometric authentication dialog
} else {
// Your application canceled the provided cancelable object
}
}
})
```
```java
// Persist activation using given PIN and ad-hoc generated biometric related key
powerAuthSDK.persistActivation(context, fragment, "Enable Biometric Authentication", "To enable biometric authentication, use the biometric sensor on your device.", pin, new IPersistActivationWithBiometricsListener() {
@Override
public void onBiometricDialogCancelled() {
// Biometric enrolment cancelled by user

This code has created activation with two factors: possession (key stored using a key derived from a device fingerprint) and knowledge (password, in our case, a simple PIN code). If you would like to enable biometric authentication support at this moment, use the following code instead of the one above:

```kotlin
// Prepare biometric prompt.
val biometricPrompt = PowerAuthBiometricPrompt.Builder(parentFragment) // You can also use fragment activity in the constructor
.setTitle("Enable Biometric Authentication")
.setDescription("To enable biometric authentication, use the biometric sensor on your device.")
.build()
// Persist activation using given PIN and biometry
val authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometricPrompt)
val cancelable = powerAuthSDK.persistActivationWithAuthentication(context, authentication, object: IPersistActivationListener {
override fun onPersistActivationSucceeded() {
// Success
}

@Override
public void onBiometricDialogSuccess() {
// success, activation has been persisted
override fun onPersistActivationFailed(error: PowerAuthErrorException) {
// Failure
}

@Override
public void onBiometricDialogFailed(@NonNull PowerAuthErrorException error) {
// failure, typically as a result of API misuse, or a biometric authentication failure
override fun onPersistActivationCancelled(userCancel: Boolean) {
if (userCancel) {
// user cancelled the biometric authentication dialog
} else {
// Your application canceled the provided cancelable object
}
}
});
})
```
<!-- end -->

Also, you can use the following code to create activation with the best granularity control:
If `PowerAuthSDK` is configured to do not authenticate on biometric key setup (e.g. `PowerAuthBiometricConfiguration` has `authenticateOnBiometricKeySetup` set to `false`), then you can use a "dummy" biometric prompt to simplify your code:

<!-- begin codetabs Kotlin Java -->
```kotlin
val authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometryFactorRelatedKey)
val result = powerAuthSDK.persistActivationWithAuthentication(context, authentication)
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
```
```java
PowerAuthAuthentication authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometryFactorRelatedKey);
int result = powerAuthSDK.persistActivationWithAuthentication(context, authentication);
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
// Prepare biometric prompt.
val biometricPrompt = PowerAuthBiometricPrompt.noPromptForBiometricKeySetup(parentFragment)
// Persist activation using given PIN and biometry
val authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometricPrompt)
val cancelable = powerAuthSDK.persistActivationWithAuthentication(context, authentication, object: IPersistActivationListener {
// Example is the same as above
})
```
<!-- end -->

Note that you currently need to obtain the biometry factor-related key yourself - you have to use `BiometricPrompt.CryptoObject` or integration with Android `KeyStore` to do so.

### Validating User Inputs

Expand Down Expand Up @@ -1483,6 +1469,49 @@ You can use our [Passphrase meter](https://github.com/wultra/passphrase-meter) l
<!-- end -->


## Working with sensitive data

The PowerAuth mobile SDK is using `SecureData` class for manage the cryptographically sensitive data, such as encryption keys. You can encounter this class in several public API functions, such as functions for managing an [external encryption key](#external-encryption-key). This chapter explains how to use the `SecureData` object properly.

### Create instance of `SecureData`

If you need to provide cryptographically sensitive key material to PowerAuth mobile SDK, then use the following code:

```kotlin
val yourKey = "nbuSR123nbuSR123".toByteArray()
val secureData = SecureData.copy(yourKey)
```

The `secureData` object will keep copy of bytes. In case you also wants to erase also the content of the source array, then you can use an alternative construction:

```kotlin
val yourKey = "nbuSR123nbuSR123".toByteArray()
val secureData = SecureData.copyAndClearSource(yourKey)
```

Finally, if you're sure that no other object retains reference to the byte array (for example, if it's returned as a result of encrypt or decrypt function), then you can use the following construction:

```kotlin
val yourKey = "nbuSR123nbuSR123".toByteArray()
val secureData = SecureData.capture(yourKey)
```

### Using instance of `SecureData`

To get reference to stored bytes, use the following code:

```swift
func processSecureData(secureData: SecureData) {
doSomethingWitBytes(secureData.sensitiveData)
}
```

<!-- begin box warning -->
Be aware that you should not keep the reference to provided byte array. If you need to keep the bytes longer, then keep the reference to `SecureData` instance, or make your own copy of bytes, returned in `sensitiveData` property.
<!-- end -->



## Biometric Authentication Setup

PowerAuth SDK for Android provides an abstraction on top of the base Biometric Authentication support. While the authentication / data signing itself is handled using the `PowerAuthAuthentication` object used in [regular request signing](#data-signing), other biometry-related processes require their own API.
Expand Down Expand Up @@ -1634,7 +1663,6 @@ powerAuthSDK.addBiometryFactor(context, fragment, "Enable Biometric Authenticati

By default, PowerAuth SDK asks the user to authenticate with the biometric sensor also during the setup procedure (or during the [activation persist](#persisting-activation-data)). To alter this behavior, use the following code to change the `PowerAuthBiometricConfiguration` provided to the `PowerAuthSDK` instance:

<!-- begin codetabs Kotlin Java -->
```kotlin
val biometricConfig = PowerAuthBiometricConfiguration.Builder()
.authenticateOnBiometricKeySetup(false)
Expand All @@ -1644,16 +1672,6 @@ val powerAuthSDK = PowerAuthSDK.Builder(configuration)
.biometricConfiguration(biometricConfig)
.build(getApplicationContext())
```
```java
PowerAuthBiometricConfiguration biometricConfig = new PowerAuthBiometricConfiguration.Builder()
.authenticateOnBiometricKeySetup(false)
.build();
// Apply keychain configuration
PowerAuthSDK powerAuthSDK = new PowerAuthSDK.Builder(configuration)
.biometricConfiguration(biometricConfig)
.build(getApplicationContext());
```
<!-- end -->

<!-- begin box info -->
Note that the RSA key pair is internally generated for the configuration above. That may take more time on older devices than the default configuration. Your application should display a waiting indicator on its own because SDK doesn't display an authentication dialog during the key-pair generation.
Expand Down Expand Up @@ -2100,7 +2118,6 @@ The secure vault mechanism does not support biometry by default. Use PIN code or

To obtain an encryption key with a given index, use the following code:

<!-- begin codetabs Kotlin Java -->
```kotlin
// 2FA signature. It uses device-related key and user PIN code.
val authentication = PowerAuthAuthentication.possessionWithPassword("1234")
Expand All @@ -2110,37 +2127,16 @@ val index = 1000L

// Fetch the encryption key with the given index
powerAuthSDK.fetchEncryptionKey(context, authentication, index, object: IFetchEncryptionKeyListener {
override fun onFetchEncryptionKeySucceed(encryptedEncryptionKey: ByteArray) {
override fun onFetchEncryptionKeySucceed(encryptionKey: SecureData) {
// ... use the encryption key to encrypt or decrypt data
val keyBytes = encryptionKey.sensitiveData
}

override fun onFetchEncryptionKeyFailed(t: Throwable) {
// Report error
}
})
```
```java
// 2FA signature. It uses device device-related key and user PIN code.
PowerAuthAuthentication authentication = PowerAuthAuthentication.possessionWithPassword("1234");

// Select custom key index
long index = 1000L;

// Fetch the encryption key with the given index
powerAuthSDK.fetchEncryptionKey(context, authentication, index, new IFetchEncryptionKeyListener() {
@Override
public void onFetchEncryptionKeySucceed(byte[] encryptedEncryptionKey) {
// ... use the encryption key to encrypt or decrypt data
}

@Override
public void onFetchEncryptionKeyFailed(Throwable t) {
// Report error
}
})
```
<!-- end -->


## Token-Based Authentication

Expand Down
Loading